-
Rolex
имя: Alex
- Ветеран
-
- Сообщения: 898
- Зарегистрирован: 22 сен 2020, 18:58
- Откуда: УКРАИНА
- Пол:
- Поблагодарили: 53 раз.
|
Rolex » 16 мар 2021, 23:19
Самый главный баг пока еще не исправлен. Если у меня кол-во отрядов меньше чем у врага и у врага стоит Magic Mirror на всех отрядах, то после того, как я направляю любой масспелл, отражение работает неправильно. Вот, например, у меня 2 отряда, у врага 4 отряда и на всех стоит Зеркало. Я кастую Замеделение, и на один вражеский отряд оно проходит и накладывается, а три вражеских отряда его отражают. Следовательно это заклинание должно наложится на три моих отряда. Но посколько кол-во моих отрядов меньше, чем кол-во отражений, значит оно должно наложится на все мои отряды, то есть на два отряда. А накладывается только на один. Или отражает два отряда, а накладывает опять же только на один. Или, например, 3 отряда против 7. 4 из 7 отражает Зеркалом, а накладывает вместо 3 отрядов всего на 1. По поводу резиста при масскасте: 1) Если все отряды отражают резистом направлямый закл, то анимация резиста сопровождается звуковым сопровождением направляемого закла. А должно как бы вместе с анимацией резиста проигрыватся и звук резиста. 2) Если один или несколько отрядов не отражают закл резистом, а один или несколько наоборот отражают, то вместе с анимацией резиста проигрывается звуковое сопровождение направляемого закла, а уже после идет анимация самого закла, но уже без звука. То есть правильней было бы изначально вместе с анимацией резиста проиграть и его озвучку, а уже после вместе с анимацией закла соответственно его звук. 3) Аналогично второму, но еще с Зеркалом. То есть изначально проигрывается анимация Зеркала для отрядов, которые отразили закл, после чего идет проигрываение анимации резиста для других отрядов и после уже наложение направляемого закла на свои и вражеские отряды. Вот здесь как раз очень хорошо заметно последовательная анимация. Задержка между отражением и наложением закла увеличивается, так как между ними еще вклинивается анимация резиста. Но основая проблема в том, что вместе с анимацией Зеркала проигрывается звук напрвляемого закла, а анимация резиста и следущая за ней анимация закла проигрываються вообще без звука. То есть правильней было проиграть анимацию Зеркала и вместе с ней ее звук, дальше анимацию резиста и ее звук и только после этого анимацию и звук направляемого закла. 4) Анимация резиста срабатывает только на тех существах у которых есть определенная вероятность отразить заклинание, например, - гномы. В тоже время как на существах с полным имуннитетом к определенным заклинаниям (Титаны) или ко всем заклинаниям до определенного уровня (драконы) или вообще ко всем заклинаниям (Черные драконы) - анимация резиста не работает при масскасте, а должна. Даже на Черных драконах должна срабатывать анимация резиста при масскасте. Просто если мы попытаемся наложить какой-то одиночной закл на Черных драконов, то мы не сможем этого сделать, а потому и не сможет увидеть анимацию резиста. В то же время в оригинале Волшебное зеркало может отразить направляемый закл на Черных драконов, да случайно выбранный отряд вполне может быть и Черным драконом, и вот в таком случае анимация резиста уже срабатывает. AlexSpl, и нужна ваша помощь в том, чтобы доделать отражение на самые сильные вражеские отряды. У меня через массив, но можете через стек, на ваше усмотрение. Главное, чтобы работало. Я пытался это сделать, как вы и советовали в ResetMagicMirrorFlags, а в getEnemyStackToRedirectTo снимал, но что-то не так. Работает неверно, либо вообще получаю вылет. Сделал свой массив глобальным и обявил еще глобальную переменную и инкрементировал ее при каждом обращении к функции getEnemyStackToRedirectTo. И, кстати, что тогда делать с хуком по адресу 0x5A05CC и функцией NewTarget, которая выбирает одиночную цель, когда нет масскаста. Просто основной код из нее ушел в ResetMagicMirrorFlags. В общем я включил ваш код в свой: - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #define AnimateStack (((bool(*)[20])&o_BattleMgr->Field<bool>(0x547C)))
#include "stdafx.h" #include "HotA\homm3.h" #include <utility> #include <iostream> #include <vector> #include <algorithm> #include <stack>
using namespace std;
Patcher* _P; PatcherInstance* _PI;
static _bool_ plugin_On = 0;
bool showMagicMirrorAnim, showMagicResistAnim; bool needMagicMirrorAnim[2][20], needMagicResistAnim[2][20];
int position; vector <pair<int, int> > combatPowerOfStacks;
struct SpellDesc { char* DefaultDesc; char* BasicDesc; char* AdvancedDesc; char* ExpertDesc; };
SpellDesc NewMagicMirror = { "{Магическое зеркало}\n\nЦелевой отряд способен отразить вражеское заклинание на самый сильный отряд противника (вместо случайного) с вероятностью в 40%.", "{Базовое Магическое зеркало}\n\nЦелевой отряд способен отразить вражеское заклинание на самый сильный отряд противника (вместо случайного) с вероятностью в 40%.", "{Продвинутое Магическое зеркало}\n\nЦелевой отряд способен отразить вражеское заклинание на самый сильный отряд противника (вместо случайного) с вероятностью в 50%.", "{Экспертное Магическое зеркало}\n\nВсе дружественные отряды способны отразить вражеское заклинание на все или самые сильные отряды противника (вместо случайного) с вероятностью в 50%." };
int __stdcall afterInit(LoHook* h, HookContext* c) { o_Spell[SPL_MAGIC_MIRROR].effect[0] = 40; o_Spell[SPL_MAGIC_MIRROR].effect[1] = 40; o_Spell[SPL_MAGIC_MIRROR].effect[2] = 50; o_Spell[SPL_MAGIC_MIRROR].effect[3] = 50;
*(SpellDesc*)(o_Spell + SPL_MAGIC_MIRROR)->description = NewMagicMirror;
return EXEC_DEFAULT; }
bool my_cmp(const pair<int, int>& a, const pair<int, int>& b) { return a.first > b.first; }
int __stdcall NewTarget(LoHook* h, HookContext* c) { int pos = 0;
combatPowerOfStacks.resize(o_BattleMgr->stacks_count[o_BattleMgr->current_side]); for (int i = 0; i < combatPowerOfStacks.size(); ++i) { _BattleStack_* stack = &o_BattleMgr->stack[o_BattleMgr->current_side][i]; combatPowerOfStacks[i].first = o_pCreatureInfo[stack->creature_id].fight_value * stack->count_current; combatPowerOfStacks[i].second = i; } sort(combatPowerOfStacks.begin(), combatPowerOfStacks.end(), my_cmp); for (int i = 0; i < combatPowerOfStacks.size(); ++i) { _BattleStack_* stack = &o_BattleMgr->stack[o_BattleMgr->current_side][combatPowerOfStacks[i].second]; if (stack->creature_id == CID_BLACK_DRAGON || stack->creature_id == CID_MAGIC_ELEMENTAL || stack->active_spell_duration[SPL_ANTI_MAGIC]) continue; else { pos = combatPowerOfStacks[i].second; break; } }
c->eax = (int)&o_BattleMgr->stack[o_BattleMgr->current_side][pos];
return EXEC_DEFAULT; }
char __stdcall IsSpellSingleTarget(HiHook *h, int spell, int ssLevel) { if (spell == SPL_MAGIC_MIRROR && ssLevel == 3) return FALSE; else return CALL_2(char, __fastcall, h->GetDefaultFunc(), spell, ssLevel); }
// -----------------
bool magicMirrorLucky(_Hero_* hero, _BattleStack_* stack, int spell) { int effSchoolLevel = CALL_3(int, __thiscall, 0x4E52F0, hero, SPL_MAGIC_MIRROR, o_BattleMgr->spec_terr_type);
return !(o_Spell[spell].flags & SPF_FRIENDLY_HAS_MASS) && stack->side != o_BattleMgr->current_side && stack->active_spell_duration[SPL_MAGIC_MIRROR] > 0 && Randint(1, 100) <= o_Spell[SPL_MAGIC_MIRROR].effect[effSchoolLevel]; }
_BattleStack_* getEnemyStackToRedirectTo(_BattleStack_* stack) { // В целях демонстрации работы просто перенаправим заклинание на вражеский отряд // с таким же индексом, как у отряда, отразившего заклинание, // поэтому тестируйте с полными армиями во избежание сюрпризов
return &o_BattleMgr->stack[1 - stack->side][stack->index_on_side]; //position++; //return &o_BattleMgr->stack[o_BattleMgr->current_side][combatPowerOfStacks[position].second]; }
int __stdcall ResetMagicMirrorFlags(LoHook* h, HookContext* c) { showMagicMirrorAnim = false; showMagicResistAnim = false; memset(needMagicMirrorAnim, false, 40); memset(needMagicResistAnim, false, 40);
// -----
combatPowerOfStacks.resize(o_BattleMgr->stacks_count[o_BattleMgr->current_side]);
for (int i = 0; i < combatPowerOfStacks.size(); ++i) { _BattleStack_* stack = &o_BattleMgr->stack[o_BattleMgr->current_side][i]; combatPowerOfStacks[i].first = o_pCreatureInfo[stack->creature_id].fight_value * stack->count_current; combatPowerOfStacks[i].second = i; }
sort(combatPowerOfStacks.begin(), combatPowerOfStacks.end(), my_cmp);
// -----
return EXEC_DEFAULT; }
int __stdcall ReflectSpell(LoHook* h, HookContext* c) { _BattleStack_* stack = (_BattleStack_*)c->esi; _BattleStack_* stackFoe;
int spell = *(int*)(c->ebp + 0xC); int spellPower = *(int*)(c->ebp + 0x14); int schoolLevel = *(int*)(c->ebp + 0x10); int casterSide = *(int*)(c->ebp + 0x18); _Hero_* hero = *(_Hero_**)(c->ebp + 8);
// Если сработало Magic Mirror, перенаправляем заклинание на вражеский отряд if (magicMirrorLucky(o_BattleMgr->hero[1 - o_BattleMgr->current_side], stack, spell)) { showMagicMirrorAnim = true; needMagicMirrorAnim[stack->side][stack->index_on_side] = true; stackFoe = getEnemyStackToRedirectTo(stack); if (stackFoe) { // Определяем, сработает ли резист против отражённого заклинания int resistPercentage = 100 * CALL_7(float, __thiscall, 0x5A83A0, o_BattleMgr, spell, casterSide, stackFoe, 1, 1, *(int*)(c->ebp + 0x1C));
if (Randint(1, 100) <= resistPercentage) { CALL_5(void, __thiscall, 0x444610, stackFoe, spell, spellPower, schoolLevel, hero); AnimateStack[stackFoe->side][stackFoe->index_on_side] = true; } else if (resistPercentage) { showMagicResistAnim = true; needMagicResistAnim[stackFoe->side][stackFoe->index_on_side] = true; } } } else { if (Randint(1, 100) <= c->eax) { // Если не сработал резист, применяем эффект заклинания CALL_5(void, __thiscall, 0x444610, stack, spell, spellPower, schoolLevel, hero); AnimateStack[stack->side][stack->index_on_side] = true; } // Если сработал резист, отмечаем отряд как требующий анимации резиста else if (c->eax) { showMagicResistAnim = true; needMagicResistAnim[stack->side][stack->index_on_side] = true; } }
c->return_address = 0x5A6A83; return NO_EXEC_DEFAULT; }
int __stdcall MagicMirrorMassReflection(LoHook* h, HookContext* c) { // Проигрываем массовую анимацию Magic Mirror if (showMagicMirrorAnim) CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needMagicMirrorAnim, o_Spell[SPL_MAGIC_MIRROR].animation_ix, 0);
// Проигрываем массовую анимацию резиста if (showMagicResistAnim) CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needMagicResistAnim, 78, 0);
return EXEC_DEFAULT; }
// -----------------
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (DLL_PROCESS_ATTACH == ul_reason_for_call) { if (!plugin_On) { plugin_On = 1; _P = GetPatcher(); _PI = _P->CreateInstance("HD.Plugin.NewMagicMirror");
_PI->WriteHiHook(0x59E360, SPLICE_, EXTENDED_, FASTCALL_, IsSpellSingleTarget); _PI->WriteLoHook(0x4EE1C1, afterInit); _PI->WriteLoHook(0x5A05CC, NewTarget);
_PI->WriteLoHook(0x5A13D2, ResetMagicMirrorFlags); _PI->WriteLoHook(0x5A6A50, ReflectSpell); _PI->WriteLoHook(0x5A13E5, MagicMirrorMassReflection); } }
return TRUE; }
|