-
AlexSpl
имя: Александр
- Эксперт
-
- Сообщения: 5587
- Зарегистрирован: 17 сен 2010, 12:58
- Пол:
- Награды: 14
-
-
- Поблагодарили: 2185 раз.
|
AlexSpl » 05 апр 2021, 14:23
Короче, фигня какая-то: Ammo Cart получает damageFightValue больше, чем 10 Архангелов... Похоже, ошибка в Вашем коде: - Код: Выделить всё
damageFightValueThem += min(spellDamage * koef * 1.0 / stack->full_hp, (stack->full_hp - stack->lost_hp) * 1.0 / stack->full_hp + (stack->count_current - 1) * 1.0) * o_pCreatureInfo[stack->creature_id].fight_value;
Первое число несопоставимо со вторым (у второго есть множитель Fight Value). Для тележки вот это: - Код: Выделить всё
spellDamage * koef * 1.0 / stack->full_hp
будет всегда больше, чем для 10 Архангелов. А так как второй аргумент min() - число очень большое, то выбран будет первый аргумент. Поэтому и предпочитает фигачить тележку вместо Архов. Версия с подробным дебагом - Код: Выделить всё
#define _CRT_RAND_S #define _CRT_SECURE_NO_WARNINGS #include "stdafx.h" #include "..\..\HotA\homm3.h" #include <vector> #include <algorithm>
using namespace std;
Patcher* _P; PatcherInstance* _PI;
struct _BattleStackEx_ : public _BattleStack_ { int getMonsterSpell(); bool approvedTarget(const int spell); bool magicMirrorLucky(const int spell); _BattleStackEx_* getStackToRedirect(const int spell, const bool massCast = true); int calcMagicDamage(const int spell, const _Hero_* attHero, const _Hero_* defHero); inline int fightValue() { return this->creature.fight_value * this->count_current; }; double damageFightValue(const int spellDamage); inline float getMagicVulnerability(const int spell) { return CALL_7(float, __thiscall, 0x5A83A0, o_BattleMgr, spell, o_BattleMgr->current_side, this, 1, 1, 0); }; inline int getHitChance(const int spell) { return (int)(100 * getMagicVulnerability(spell)); } inline bool isImmuneTo(const int spell) { return getMagicVulnerability(spell) == 0; }; inline void playAnimation(const int id) { CALL_5(void, __thiscall, 0x4963C0, o_BattleMgr, id, this, 100, 0); } };
bool showMagicMirrorAnim, showMagicResistAnim, showSpellAnim, redirectedAreaSpell; bool needMagicMirrorAnim[2][20], needMagicResistAnim[2][20], needSpellAnim[2][20]; vector<_BattleStackEx_*> stackVector; int stackIndex;
#define SPL_DEATH_RIPPLE 24 #define CID_AZURE_DRAGON 132
#define AnimateStack (((bool(*)[20])&o_BattleMgr->Field<bool>(0x547C)))
enum A {A_REFLECTSPELL_HOOK, A_MASSREFLECTION_HOOK, A_REFLECTSPELL_SKIP, A_REFLECTSPELL_DEFAULT, A_MASSANIMATION}; enum E {E_MASS, E_BERSERK, E_AREA, E_DEATH_RIPPLE, E_DESTROY_UNDEAD, E_ARMAGEDDON, E_SIZE};
const _ptr_ hAddr[][E_SIZE] = { {0x5A6A50, 0x5A20F4, 0x5A4D74, 0x5A1006, 0x5A1203, 0x5A4F4E}, // A_REFLECTSPELL_HOOK {0x5A13E5, 0x5A2156, 0x5A4C80, 0x5A1151, 0x5A12BD, 0x5A4FFF}, // A_MASSREFLECTION_HOOK {0x5A6A83, 0x5A210E, 0x5A4D89, 0x5A107B, 0x5A1278, 0x5A4FBB}, // A_REFLECTSPELL_SKIP {0x000000, 0x000000, 0x5A4DA8, 0x5A1020, 0x5A121D, 0x5A4F63}, // A_REFLECTSPELL_DEFAULT {0x5A13FC, 0x5A2168, 0x000000, 0x5A116F, 0x5A12E0, 0x000000} // A_MASSANIMATION };
struct SpellDesc { char* DefaultDesc; char* BasicDesc; char* AdvancedDesc; char* ExpertDesc; };
SpellDesc NewMagicMirrorRus = { "{Магическое зеркало}\n\nЦелевой отряд способен отразить вражеское заклинание на самый сильный отряд противника с вероятностью в 40%.", "{Базовое Магическое зеркало}\n\nЦелевой отряд способен отразить вражеское заклинание на самый сильный отряд противника с вероятностью в 40%.", "{Продвинутое Магическое зеркало}\n\nЦелевой отряд способен отразить вражеское заклинание на самый сильный отряд противника с вероятностью в 50%.", "{Экспертное Магическое зеркало}\n\nВсе дружественные отряды способны отразить вражеское заклинание на все или самые сильные отряды противника с вероятностью в 50%." };
SpellDesc NewMagicMirrorEng = { "{Magic Mirror}\n\nThe target stack is able to reflect the enemy spell on the strongest enemy stack with a 40% chance.", "{Basic Magic Mirror}\n\nThe target stack is able to reflect the enemy spell on the strongest enemy stack with a 40% chance.", "{Advanced Magic Mirror}\n\nThe target stack is able to reflect the enemy spell on the strongest enemy stack with a 50% chance.", "{Expert Magic Mirror}\n\nAll friendly stacks are able to reflect an enemy spell on all or the most strongest enemy stacks with a 50% chance." };
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 = o_CreatureInfo[0].name_single[0] != 'P' ? NewMagicMirrorRus : NewMagicMirrorEng;
return EXEC_DEFAULT; }
int Randint_s() { unsigned dice; rand_s(&dice); return (int)((double)dice / ((double)UINT_MAX + 1) * 100.0) + 1; }
void showDebugInfo(const char* format, ...) { va_list args; va_start(args, format);
vsprintf(o_TextBuffer, format, args); b_MsgBox(o_TextBuffer, MBX_OK);
va_end(args); }
_ptr_ getRA(const int spell) { _ptr_ retAddr;
switch ( spell ) { case SPL_FROST_RING: case SPL_FIREBALL: case SPL_INFERNO: case SPL_METEOR_SHOWER: retAddr = hAddr[A_REFLECTSPELL_DEFAULT][E_AREA]; break; case SPL_DEATH_RIPPLE: retAddr = hAddr[A_REFLECTSPELL_DEFAULT][E_DEATH_RIPPLE]; break; case SPL_DESTROY_UNDEAD: retAddr = hAddr[A_REFLECTSPELL_DEFAULT][E_DESTROY_UNDEAD]; break; case SPL_ARMAGEDDON: retAddr = hAddr[A_REFLECTSPELL_DEFAULT][E_ARMAGEDDON]; break; } return retAddr; }
bool _BattleStackEx_::approvedTarget(const int spell) { return !this->is_killed && !this->isImmuneTo(spell) && !(spell == SPL_FORGETFULNESS && this->creature.shots == 0); }
bool _BattleStackEx_::magicMirrorLucky(const int spell) { int effSchoolLevel = this->active_spells_power[SPL_MAGIC_MIRROR];
return !this->isImmuneTo(spell) && !(o_Spell[spell].flags & SPF_FRIENDLY_HAS_MASS) && (this->side != o_BattleMgr->current_side || spell == SPL_FROST_RING || spell == SPL_FIREBALL || spell == SPL_INFERNO || spell == SPL_METEOR_SHOWER || spell == SPL_BERSERK || spell == SPL_DEATH_RIPPLE || spell == SPL_DESTROY_UNDEAD || spell == SPL_ARMAGEDDON) && this->active_spell_duration[SPL_MAGIC_MIRROR] > 0 && Randint_s() <= o_Spell[SPL_MAGIC_MIRROR].effect[effSchoolLevel]; }
_BattleStackEx_* _BattleStackEx_::getStackToRedirect(const int spell, const bool massCast) { _BattleStackEx_* stackFoe = 0; int sideFoe = 1 - this->side;
if ( stackIndex < (int)stackVector.size() && spell != SPL_DESTROY_UNDEAD && spell != SPL_DEATH_RIPPLE && spell != SPL_ARMAGEDDON ) stackFoe = (_BattleStackEx_*)&o_BattleMgr->stack[sideFoe][stackVector[stackIndex++]->index_on_side];
if ( !massCast && !stackFoe ) { int i = 0; // Пропускаем погибшие отряды while ( o_BattleMgr->stack[o_BattleMgr->current_side][i].is_killed ) ++i; stackFoe = (_BattleStackEx_*)&o_BattleMgr->stack[sideFoe][i]; } return stackFoe; }
int _BattleStackEx_::calcMagicDamage(const int spell, const _Hero_* attHero, const _Hero_* defHero) { int effSchoolLevel = 0; if ( attHero ) effSchoolLevel = CALL_3(int, __thiscall, 0x4E52F0, attHero, spell, o_BattleMgr->spec_terr_type); // Если кастер - нейтралы на Magic Plains else if ( o_BattleMgr->spec_terr_type == 1 ) effSchoolLevel = 3;
int damage = attHero->power * o_Spell[spell].eff_power + o_Spell[spell].effect[effSchoolLevel]; return CALL_7(int, __thiscall, 0x5A7BF0, o_BattleMgr, damage, spell, attHero, defHero, this, 0); }
double _BattleStackEx_::damageFightValue(const int spellDamage) { double dmgFightValue;
// Если урон заклинания в точности равен здоровью отряда if ( spellDamage == this->count_current * this->full_hp - this->lost_hp ) dmgFightValue = this->fightValue(); else dmgFightValue = min((double)spellDamage / this->full_hp, this->count_current - (double)this->lost_hp / this->full_hp) * this->creature.fight_value;
return dmgFightValue; }
int __stdcall newTarget(LoHook* h, HookContext* c) { _BattleStackEx_* stack = (_BattleStackEx_*)c->edi; int spell = *(int*)(c->ebp + 8);
c->eax = (int)stack->getStackToRedirect(spell, false);
return EXEC_DEFAULT; }
bool __stdcall massSpellMagicMirror(HiHook *h, int spell, int ssLevel) { return spell == SPL_MAGIC_MIRROR && ssLevel == 3 ? false : CALL_2(bool, __fastcall, h->GetDefaultFunc(), spell, ssLevel); }
bool cmpFightValue(_BattleStackEx_* a, _BattleStackEx_* b) { return a->creature.fight_value * a->count_current > b->creature.fight_value * b->count_current; }
// Костыль для C++98 class cmpSpellDuration { int spell;
public: cmpSpellDuration(int id) : spell(id) { }
bool operator () (_BattleStackEx_* a, _BattleStackEx_* b) { return a->active_spell_duration[spell] < b->active_spell_duration[spell]; } };
int __stdcall skipSpellSound(LoHook* h, HookContext* c) { if ( !c->edi ) { int spell = *(int*)(c->ebp + 8); char switchCase = ((char*)0x5A2B48)[spell - 10];
// При следующих условиях не проигрываем звук заклинания if ( spell == SPL_DEATH_RIPPLE || spell == SPL_DESTROY_UNDEAD || switchCase == 17 || switchCase == 24 || o_BattleMgr->ShouldNotRenderBattle() ) { c->return_address = 0x5A0646; return NO_EXEC_DEFAULT; } }
return EXEC_DEFAULT; }
int _BattleStackEx_::getMonsterSpell() { int spell = ID_NONE;
if ( this ) { switch ( this->creature_id ) { case CID_THUNDERBIRD: spell = SPL_LIGHTNING_BOLT; break; case CID_DRAGON_FLY: spell = SPL_WEAKNESS; break; case CID_UNICORN: case CID_WAR_UNICORN: spell = SPL_BLIND; break; case CID_BLACK_KNIGHT: case CID_DREAD_KNIGHT: case CID_MUMMY: spell = SPL_CURSE; break; } }
return spell; }
int __stdcall dataInit(LoHook* h, HookContext* c) { int spell; if ( h->GetAddress() == 0x5A058B ) spell = *(int*)(c->ebp + 8); else { _BattleStackEx_* stack = (_BattleStackEx_*)c->esi; spell = stack->getMonsterSpell(); }
if ( spell != ID_NONE ) { showMagicMirrorAnim = false; showMagicResistAnim = false; showSpellAnim = false; redirectedAreaSpell = false; memset(needMagicMirrorAnim, false, 40); memset(needMagicResistAnim, false, 40); memset(needSpellAnim, false, 40);
int casterSide = o_BattleMgr->current_side; int maxSize = o_BattleMgr->stacks_count[casterSide]; stackVector.resize(maxSize);
int n = 0; for (int i = 0; i < maxSize; ++i) { _BattleStackEx_* stack = (_BattleStackEx_*)&o_BattleMgr->stack[casterSide][i]; if ( stack->approvedTarget(spell) ) stackVector[n++] = stack; }
stackVector.resize(n); sort(stackVector.begin(), stackVector.end(), cmpFightValue); stable_sort(stackVector.begin(), stackVector.end(), cmpSpellDuration(spell));
stackIndex = 0; }
return EXEC_DEFAULT; }
int __stdcall magicMirrorAI(LoHook* h, HookContext* c) { _BattleStackEx_* stack = (_BattleStackEx_*)c->edi;
if ( stack ) { _Hero_* hero = o_BattleMgr->hero[1 - o_BattleMgr->current_side]; int spell = *(int*)(c->ebp + 8); int effSchoolLevel = stack->active_spells_power[SPL_MAGIC_MIRROR];
// Если герой - AI, на отряде висит Magic Mirror и оно сработало, а также оригинальные проверки на Teleport и Sacrifice if ( !CALL_2(bool, __thiscall, 0x4CE600, o_GameMgr, o_BattleMgr->owner_id[o_BattleMgr->current_side]) && stack->active_spell_duration[SPL_MAGIC_MIRROR] > 0 && Randint_s() <= o_Spell[SPL_MAGIC_MIRROR].effect[effSchoolLevel] && spell != SPL_TELEPORT && spell != SPL_SACRIFICE ) { // Проигрываем одиночную анимацию CALL_5(void, __thiscall, 0x4963C0, o_BattleMgr, o_Spell[SPL_MAGIC_MIRROR].animation_ix, c->edi, 100, 0);
c->return_address = 0x5A05CC; return NO_EXEC_DEFAULT; } } return EXEC_DEFAULT; }
void playSound(const char* fileName) { CALL_1(_Sample_, __fastcall, 0x59A770, fileName); }
void playMagicResist() { // Проигрываем массовую анимацию и звук резиста if ( showMagicResistAnim ) { playSound("MagicRes.wav"); CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needMagicResistAnim, 78, 0); } }
void playMagicMirror() { // Проигрываем массовую анимацию и звук Magic Mirror if ( showMagicMirrorAnim ) { playSound(o_Spell[SPL_MAGIC_MIRROR].wav_name); CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needMagicMirrorAnim, o_Spell[SPL_MAGIC_MIRROR].animation_ix, 0); } }
int __stdcall massReflection(LoHook* h, HookContext* c) { bool hitFlag = false; _ptr_ addr = h->GetAddress();
if ( addr == hAddr[A_MASSREFLECTION_HOOK][E_MASS] ) c->return_address = hAddr[A_MASSANIMATION][E_MASS]; if ( addr == hAddr[A_MASSREFLECTION_HOOK][E_BERSERK] ) c->return_address = hAddr[A_MASSANIMATION][E_BERSERK]; if ( addr == hAddr[A_MASSREFLECTION_HOOK][E_DEATH_RIPPLE] ) { hitFlag = true; c->return_address = hAddr[A_MASSANIMATION][E_DEATH_RIPPLE]; }
if ( addr == hAddr[A_MASSREFLECTION_HOOK][E_DESTROY_UNDEAD] ) { c->edi = *(int*)(c->ebp - 0x10); hitFlag = true; c->return_address = hAddr[A_MASSANIMATION][E_DESTROY_UNDEAD]; }
playMagicMirror(); playMagicResist(); if ( addr == hAddr[A_MASSREFLECTION_HOOK][E_ARMAGEDDON] ) { memcpy(AnimateStack, needSpellAnim, 40); return EXEC_DEFAULT; }
// Проигрываем массовую анимацию и звук кастуемого заклинания if ( showSpellAnim ) { _Spell_* spell = (_Spell_*)*(int*)(c->ebp - 0x10); playSound(spell->wav_name); CALL_4(void, __thiscall, 0x5A6AD0, o_BattleMgr, &needSpellAnim, spell->animation_ix, hitFlag); }
return NO_EXEC_DEFAULT; }
bool isValidHex(const int hex) { return hex >= 0 && hex < 187; }
int getSpellTargetHex(const int spell) { const int xSize = 17; double maxDamageFightValueDelta = 0.0; int bestTargetHex = -1;
_Hero_* attHero = o_BattleMgr->hero[o_BattleMgr->current_side]; _Hero_* defHero = o_BattleMgr->hero[1 - o_BattleMgr->current_side];
for (int hex = 1; ; ++hex) { if ( hex % xSize == 16 ) hex += 2; if ( hex > 185 ) break; int y = hex / xSize; int d = y % 2;
int areaR1[] = {-17 - d, -16 - d, -1, 0, 1, 17 - d, 18 - d}; int areaFR[] = {-17 - d, -16 - d, -1, 1, 17 - d, 18 - d}; int areaR2[] = {-35, -34, -33, -18 - d, -17 - d, -16 - d, -15 - d, -2, -1, 0, 1, 2, 16 - d, 17 - d, 18 - d, 19 - d, 33, 34, 35}; int* area = areaR1; int areaSize = sizeof(areaR1) / sizeof(int); if ( spell == SPL_FROST_RING ) { area = areaFR; areaSize = sizeof(areaFR) / sizeof(int); }
if ( spell == SPL_INFERNO ) { area = areaR2; areaSize = sizeof(areaR2) / sizeof(int); } int countUs = 0, countThem = 0; double damageFightValueUs = 0.0, damageFightValueThem = 0.0; for (int i = 0; i < areaSize; ++i) { int iHex = hex + area[i]; if ( isValidHex(iHex) ) { _BattleStackEx_* stack = (_BattleStackEx_*)o_BattleMgr->hex[iHex].GetCreature(); if ( stack ) { if ( !stack->is_killed && !stack->isImmuneTo(spell) ) { // Считаем магический урон, получаемый стеком stack int spellDamage = stack->calcMagicDamage(spell, attHero, defHero);
if ( stack->side == o_BattleMgr->current_side ) { ++countThem; damageFightValueThem += stack->damageFightValue(spellDamage); } else { ++countUs; damageFightValueUs += stack->damageFightValue(spellDamage); }
// Debug (проверяем урон) showDebugInfo("{Epicenter Hex = %d}\n\nArea Hex = %d\n%d %s: %d\nThem = %0.2f\nUs = %0.2f", hex, iHex, stack->count_current, GetCreatureName(stack->creature_id, stack->count_current), spellDamage, damageFightValueThem, damageFightValueUs); } if ( i + 1 < areaSize ) { int iHexNext = hex + area[i + 1]; if ( isValidHex(iHexNext) && (_BattleStackEx_*)o_BattleMgr->hex[iHexNext].GetCreature() == stack ) ++i; } } } }
if ( countThem + countUs > 0 && damageFightValueThem - damageFightValueUs > maxDamageFightValueDelta ) { maxDamageFightValueDelta = damageFightValueThem - damageFightValueUs; bestTargetHex = hex;
// Debug (проверяем damageFightValue) showDebugInfo("{NEW MAX FOUND!\nEpicenter Hex = %d}\nx = %d, y = %d\n\nThem = %0.2f\nUs = %0.2f\nThem - Us = %0.2f\nMax = %0.2f", hex, hex % 17, hex / 17, damageFightValueThem, damageFightValueUs, damageFightValueThem - damageFightValueUs, maxDamageFightValueDelta); } }
return bestTargetHex; }
void __stdcall areaReflection(HiHook* h, _BattleMgr_* battleMgr, int hex, int spell, int a3, int a4) { memcpy(AnimateStack, needSpellAnim, 40); CALL_5(void, __thiscall, h->GetDefaultFunc(), battleMgr, hex, spell, a3, a4); playMagicResist(); playMagicMirror();
// Если заклинание отражено if ( redirectedAreaSpell ) { int bestHex = getSpellTargetHex(spell); if ( bestHex != ID_NONE ) { showMagicMirrorAnim = false; showMagicResistAnim = false; memset(needMagicMirrorAnim, false, 40); memset(needMagicResistAnim, false, 40);
playSound(o_Spell[spell].wav_name); CALL_5(void, __thiscall, h->GetDefaultFunc(), battleMgr, bestHex, spell, a3, a4); playMagicResist(); playMagicMirror(); } } }
int __stdcall playMagicMirrorSound(LoHook* h, HookContext* c) { playSound(o_Spell[SPL_MAGIC_MIRROR].wav_name); return EXEC_DEFAULT; }
int __stdcall reflectSpell(LoHook* h, HookContext* c) { _Hero_* hero = 0; _BattleStackEx_* stack = 0; int spell, spellPower, schoolLevel; int casterSide = o_BattleMgr->current_side;
_ptr_ addr = h->GetAddress();
if ( addr == hAddr[A_REFLECTSPELL_HOOK][E_MASS] ) { stack = (_BattleStackEx_*)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 = hAddr[A_REFLECTSPELL_SKIP][E_MASS]; }
if ( addr == hAddr[A_REFLECTSPELL_HOOK][E_BERSERK] ) { stack = *(_BattleStackEx_**)(c->ebp + 0x14); spell = *(int*)(c->ebp + 8); spellPower = *(int*)(c->ebp + 0x1C); schoolLevel = c->esi; hero = *(_Hero_**)(c->ebp - 0x14); c->return_address = hAddr[A_REFLECTSPELL_SKIP][E_BERSERK]; }
if ( addr == hAddr[A_REFLECTSPELL_HOOK][E_AREA] ) { stack = (_BattleStackEx_*)c->edi; spell = c->esi; schoolLevel = *(int*)(c->ebp - 0x44); c->return_address = hAddr[A_REFLECTSPELL_SKIP][E_AREA]; }
if ( addr == hAddr[A_REFLECTSPELL_HOOK][E_DEATH_RIPPLE] ) { stack = (_BattleStackEx_*)c->edi; spell = SPL_DEATH_RIPPLE; c->return_address = hAddr[A_REFLECTSPELL_SKIP][E_DEATH_RIPPLE]; }
if ( addr == hAddr[A_REFLECTSPELL_HOOK][E_DESTROY_UNDEAD] ) { stack = (_BattleStackEx_*)c->edi; spell = SPL_DESTROY_UNDEAD; c->return_address = hAddr[A_REFLECTSPELL_SKIP][E_DESTROY_UNDEAD]; }
if ( addr == hAddr[A_REFLECTSPELL_HOOK][E_ARMAGEDDON] ) { stack = (_BattleStackEx_*)c->esi; spell = SPL_ARMAGEDDON; c->return_address = hAddr[A_REFLECTSPELL_SKIP][E_ARMAGEDDON]; }
// Получаем оригинальный шанс срабатывания заклинания int hitChance = c->eax;
if ( stack ) { bool isSpellAoE = spell == SPL_FROST_RING || spell == SPL_FIREBALL || spell == SPL_INFERNO || spell == SPL_METEOR_SHOWER; bool isSpellSpec = spell == SPL_DEATH_RIPPLE || spell == SPL_DESTROY_UNDEAD || spell == SPL_ARMAGEDDON;
if ( stack->magicMirrorLucky(spell) ) { _BattleStackEx_* stackFoe = stack->getStackToRedirect(spell);
if ( stackFoe && !redirectedAreaSpell ) { showMagicMirrorAnim = true; needMagicMirrorAnim[stack->side][stack->index_on_side] = true; } else { showMagicResistAnim = true; needMagicResistAnim[stack->side][stack->index_on_side] = true; }
// Не перенаправляем площадные заклинания, отражённые от дружественных отрядов if ( !(isSpellAoE && stack->side == casterSide) ) redirectedAreaSpell = true; if ( isSpellAoE || isSpellSpec ) return NO_EXEC_DEFAULT;
// Если сработало Magic Mirror, перенаправляем заклинание на вражеский отряд if ( stackFoe ) { // Определяем, сработает ли резист против отражённого заклинания int hitChanceFoe = stackFoe->getHitChance(spell);
if ( Randint_s() <= hitChanceFoe ) { showSpellAnim = true; needSpellAnim[stackFoe->side][stackFoe->index_on_side] = true; CALL_5(void, __thiscall, 0x444610, stackFoe, spell, spellPower, schoolLevel, hero); } else if ( hitChanceFoe ) { showMagicResistAnim = true; needMagicResistAnim[stackFoe->side][stackFoe->index_on_side] = true; } } } else { if ( Randint_s() <= hitChance ) { showSpellAnim = true; needSpellAnim[stack->side][stack->index_on_side] = true;
if ( isSpellAoE || isSpellSpec ) { c->return_address = getRA(spell); return NO_EXEC_DEFAULT; } // Если не сработал резист, применяем эффект заклинания CALL_5(void, __thiscall, 0x444610, stack, spell, spellPower, schoolLevel, hero); } else if ( hitChance ) { showMagicResistAnim = true; needMagicResistAnim[stack->side][stack->index_on_side] = true; } } } return NO_EXEC_DEFAULT; }
int __stdcall mirrorMonsterSpell(LoHook* h, HookContext* c) { int spell; _BattleStackEx_* stack = (_BattleStackEx_*)c->edi;
_ptr_ addrHit, addrSkip; switch ( h->GetAddress() ) { case 0x440EE8: spell = SPL_LIGHTNING_BOLT; addrHit = 0x440F03; addrSkip = 0x4412AB; break; case 0x440372: spell = SPL_BLIND; addrHit = 0x44038D; addrSkip = 0x4402AE; break; case 0x4404DB: spell = SPL_CURSE; addrHit = 0x4404F6; addrSkip = 0x4402AE; break; }
if ( stack->magicMirrorLucky(spell) ) { c->return_address = addrSkip; playSound(o_Spell[SPL_MAGIC_MIRROR].wav_name); stack->playAnimation(o_Spell[SPL_MAGIC_MIRROR].animation_ix); // Если сработало Magic Mirror, перенаправляем заклинание на вражеский отряд _BattleStackEx_* stackFoe = stack->getStackToRedirect(spell, false); if ( stackFoe ) { // Определяем, сработает ли резист против отражённого заклинания int hitChanceFoe = stackFoe->getHitChance(spell);
if ( Randint_s() <= hitChanceFoe ) { c->edi = (int)stackFoe; c->return_address = addrHit; } else if ( hitChanceFoe ) { playSound("MagicRes.wav"); stackFoe->playAnimation(78); } } return NO_EXEC_DEFAULT; } 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.NewMagicMirrorBeta");
// Пропускаем оригинальный звук заклинания, чтобы воспроизвезти его позже _PI->WriteLoHook(0x5A0634, skipSpellSound); // Инициализируем данные _PI->WriteLoHook(0x441893, dataInit); _PI->WriteLoHook(0x441991, dataInit); _PI->WriteLoHook(0x5A058B, dataInit); // Синглкаст _PI->WriteLoHook(0x5A05CC, newTarget); _PI->WriteLoHook(0x5A058B, magicMirrorAI);
// Масскаст for (int i = 0; i < E_SIZE; ++i) { _PI->WriteLoHook(hAddr[A_REFLECTSPELL_HOOK][i], reflectSpell); if ( i == E_AREA ) _PI->WriteHiHook(hAddr[A_MASSREFLECTION_HOOK][i], SPLICE_, EXTENDED_, THISCALL_, areaReflection); else _PI->WriteLoHook(hAddr[A_MASSREFLECTION_HOOK][i], massReflection); } // Проигрываем звук Magic Mirror при отражении одиночного заклинания _PI->WriteLoHook(0x5A059A, playMagicMirrorSound);
_PI->WriteLoHook(0x4EE1C1, afterInit); _PI->WriteHiHook(0x59E360, SPLICE_, EXTENDED_, FASTCALL_, massSpellMagicMirror);
_PI->WriteLoHook(0x440EE8, mirrorMonsterSpell); // Thunderstrike _PI->WriteLoHook(0x440372, mirrorMonsterSpell); // Blind _PI->WriteLoHook(0x4404DB, mirrorMonsterSpell); // Curse } }
return TRUE; }
Так. Кажется, нашёл, в чём проблема. Я не туда скобку поставил. Извиняюсь
Последний раз редактировалось AlexSpl 05 апр 2021, 15:02, всего редактировалось 2 раз(а).
|