- Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include "..\..\HotA\homm3.h"
Patcher* _P;
PatcherInstance* _PI;
bool showMagicMirrorAnim, showMagicResistAnim, showSpellAnim;
bool needMagicMirrorAnim[2][20], needMagicResistAnim[2][20], needSpellAnim[2][20];
int stackIndex;
bool magicMirrorLucky(_BattleStack_* stack, int spell)
{
int effSchoolLevel = CALL_3(int, __thiscall, 0x4E52F0, o_BattleMgr->hero[stack->side], SPL_MAGIC_MIRROR, o_BattleMgr->spec_terr_type);
return !(o_Spell[spell].flags & SPF_FRIENDLY_HAS_MASS) && (stack->side != o_BattleMgr->current_side || spell == SPL_BERSERK ) &&
stack->active_spell_duration[SPL_MAGIC_MIRROR] > 0 && Randint(1, 100) <= o_Spell[SPL_MAGIC_MIRROR].effect[effSchoolLevel];
}
_BattleStack_* getEnemyStackToRedirectTo(_BattleStack_* stack, int spell)
{
// В целях демонстрации работы просто перенаправим заклинание на первый доступный вражеский отряд
int sideFoe = 1 - stack->side;
_BattleStack_* stackFoe = stackIndex < o_BattleMgr->stacks_count[sideFoe] &&
!o_BattleMgr->stack[sideFoe][stackIndex].is_killed ? &o_BattleMgr->stack[sideFoe][stackIndex] : 0;
++stackIndex;
return stackFoe;
}
int __stdcall dataInit(LoHook* h, HookContext* c)
{
showMagicMirrorAnim = false;
showMagicResistAnim = false;
showSpellAnim = false;
memset(needMagicMirrorAnim, false, 40);
memset(needMagicResistAnim, false, 40);
memset(needSpellAnim, false, 40);
stackIndex = 0;
return EXEC_DEFAULT;
}
int __stdcall skipOrigSound(LoHook* h, HookContext* c)
{
char switchCase = ((char*)0x5A2B48)[*(int*)(c->ebp + 8) - 0xA];
if ( !c->edi && (switchCase == 0x11 || switchCase == 0x18) || o_BattleMgr->ShouldNotRenderBattle() )
{
c->return_address = 0x5A0646;
return NO_EXEC_DEFAULT;
}
return EXEC_DEFAULT;
}
int __stdcall reflectSpell(LoHook* h, HookContext* c)
{
_Hero_* hero;
_BattleStack_* stack;
int spell, spellPower, schoolLevel;
int casterSide = o_BattleMgr->current_side;
if ( h->GetAddress() == 0x5A6A50 ) {
stack = (_BattleStack_*)c->esi;
spell = *(int*)(c->ebp + 0xC);
spellPower = *(int*)(c->ebp + 0x14);
schoolLevel = *(int*)(c->ebp + 0x10);
hero = *(_Hero_**)(c->ebp + 8);
c->return_address = 0x5A6A83;
} else {
stack = *(_BattleStack_**)(c->ebp + 0x14);
spell = *(int*)(c->ebp + 8);
spellPower = *(int*)(c->ebp + 0x1C);
schoolLevel = c->esi;
hero = *(_Hero_**)(c->ebp - 0x14);
c->return_address = 0x5A210E;
}
// Если сработало Magic Mirror, перенаправляем заклинание на вражеский отряд
if ( magicMirrorLucky(stack, spell) )
{
showMagicMirrorAnim = true;
needMagicMirrorAnim[stack->side][stack->index_on_side] = true;
_BattleStack_* stackFoe = getEnemyStackToRedirectTo(stack, spell);
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);
showSpellAnim = true;
needSpellAnim[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);
showSpellAnim = true;
needSpellAnim[stack->side][stack->index_on_side] = true;
}
// Если сработал резист, отмечаем отряд как требующий анимации резиста
else if ( c->eax )
{
showMagicResistAnim = true;
needMagicResistAnim[stack->side][stack->index_on_side] = true;
}
}
return NO_EXEC_DEFAULT;
}
int __stdcall massReflection(LoHook* h, HookContext* c)
{
// Проигрываем массовую анимацию и звук Magic Mirror
if ( showMagicMirrorAnim )
{
CALL_3(void, __fastcall, 0x59A890, o_Spell[SPL_MAGIC_MIRROR].wav_name, -1, 3);
CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needMagicMirrorAnim, o_Spell[SPL_MAGIC_MIRROR].animation_ix, 0);
}
// Проигрываем массовую анимацию и звук резиста
if ( showMagicResistAnim )
{
CALL_3(void, __fastcall, 0x59A890, "MagicRes.wav", -1, 3);
CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needMagicResistAnim, 78, 0);
}
// Проигрываем массовую анимацию и звук кастуемого заклинания
if ( showSpellAnim )
{
_Spell_* spell = (_Spell_*)*(int*)(c->ebp - 0x10);
CALL_3(void, __fastcall, 0x59A890, spell->wav_name, -1, 3);
CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needSpellAnim, spell->animation_ix, 0);
}
c->return_address = h->GetAddress() == 0x5A2156 ? 0x5A2168 : 0x5A13FC;
return NO_EXEC_DEFAULT;
}
int __stdcall playMagicMirrorSound(LoHook* h, HookContext* c)
{
CALL_3(void, __fastcall, 0x59A890, o_Spell[SPL_MAGIC_MIRROR].wav_name, -1, 3);
return EXEC_DEFAULT;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
static bool plugin_On = false;
if ( DLL_PROCESS_ATTACH == ul_reason_for_call )
{
if ( !plugin_On )
{
plugin_On = true;
_P = GetPatcher();
_PI = _P->CreateInstance((char*)"HD.Plugin.NewMagicMirrorTest");
_PI->WriteLoHook(0x5A13D2, dataInit);
_PI->WriteLoHook(0x5A20BB, dataInit);
_PI->WriteLoHook(0x5A6A50, reflectSpell);
_PI->WriteLoHook(0x5A20F4, reflectSpell);
_PI->WriteLoHook(0x5A13E5, massReflection);
_PI->WriteLoHook(0x5A2156, massReflection);
// Проигрываем звук Magic Mirror при отражении одиночного заклинания
_PI->WriteLoHook(0x5A059A, playMagicMirrorSound);
// Пропускаем оригинальный звук заклинания, чтобы воспроизвезти его позже
_PI->WriteLoHook(0x5A0634, skipOrigSound);
}
}
return TRUE;
}
Дамажащие заклы позже посмотрю. Одиночный Берсерк тоже не смотрел пока. В FizMiG'е только про Гипноз написано.
* * *
Странно. У меня одиночный Берсерк отражается. Это в оригинале так или я случаем захватил и одиночный каст, являющийся подмножеством площадного?