-
Rolex
имя: Alex
- Ветеран
-
- Сообщения: 898
- Зарегистрирован: 22 сен 2020, 18:58
- Откуда: УКРАИНА
- Пол:
- Поблагодарили: 53 раз.
|
Rolex » 17 апр 2021, 13:44
Убрал #define _CRT_RAND_S и функцию showDebugInfo и заменил Randint(1, 100) на Mersenne Twister. Код - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "stdafx.h" #include "HotA\homm3.h" #include <vector> #include <algorithm> #include <random>
using namespace std;
Patcher* _P; PatcherInstance* _PI;
random_device rd; mt19937 gen(rd()); uniform_int_distribution<int> uid(1, 100);
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); float getFullVulnerability(const int spell);
inline int current_health() { return this->count_current * this->full_hp - this->lost_hp; } inline int full_health() { return this->count_current * this->full_hp; } inline int fightValue() { return this->creature.fight_value * this->count_current; }; inline double damageFightValue(const int spell, const int spellDamage) { return this->getFullVulnerability(spell) * min((double)spellDamage / this->full_hp, this->count_current - (double)this->lost_hp / this->full_hp) * this->creature.fight_value; } inline double extraFightValue(const int spell, const int spellDamage) { return spellDamage % this->full_hp >= this->full_hp - this->lost_hp && spellDamage < this->current_health() ? this->getFullVulnerability(spell) * this->creature.fight_value : 0; } 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 getHitChanceResist(const int spell) { return (int)(100 * getMagicVulnerability(spell)); } inline int getHitChanceFull(const int spell) { return (int)(100 * getFullVulnerability(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); } };
class cmpFightValue { int spell;
public: cmpFightValue(int id) : spell(id) { }
bool operator () (_BattleStackEx_* a, _BattleStackEx_* b) { return a->getFullVulnerability(spell) * a->fightValue() > b->getFullVulnerability(spell) * b->fightValue(); } };
class cmpDamageFightValue { int spell; _Hero_* attHero; _Hero_* defHero;
public: cmpDamageFightValue(int id, _Hero_* aHero, _Hero_* dHero) : spell(id), attHero(aHero), defHero(dHero) { }
bool operator () (_BattleStackEx_* a, _BattleStackEx_* b) { return a->damageFightValue(spell, a->calcMagicDamage(spell, attHero, defHero)) > b->damageFightValue(spell, b->calcMagicDamage(spell, attHero, defHero)); } };
class cmpExtraFightValue { int spell; _Hero_* attHero; _Hero_* defHero;
public: cmpExtraFightValue(int id, _Hero_* aHero, _Hero_* dHero) : spell(id), attHero(aHero), defHero(dHero) { }
bool operator () (_BattleStackEx_* a, _BattleStackEx_* b) { return a->extraFightValue(spell, a->calcMagicDamage(spell, attHero, defHero)) > b->extraFightValue(spell, b->calcMagicDamage(spell, attHero, defHero)); } };
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]; } };
bool showMagicMirrorAnim, showMagicResistAnim, showSpellAnim; bool redirectedSingleCast, redirectedAreaSpell; bool showResistAfterAttack = false, showMagicMirrorAfterAttack = false; bool needMagicMirrorAnim[2][20], needMagicResistAnim[2][20], needSpellAnim[2][20]; _BattleStackEx_* targetStack = 0;
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; }
_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) && !this->active_spell_duration[SPL_BLIND] && !this->active_spell_duration[SPL_STONE] && !this->active_spell_duration[SPL_PARALYZE]; }
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 && uid(gen) <= 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; }
float _BattleStackEx_::getFullVulnerability(const int spell) { float magicMirrorChance = this->active_spell_duration[SPL_MAGIC_MIRROR] ? o_Spell[SPL_MAGIC_MIRROR].effect[this->active_spells_power[SPL_MAGIC_MIRROR]] * 0.01f : 0; return (1 - magicMirrorChance) * this->getMagicVulnerability(spell); };
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); }
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); redirectedSingleCast = true;
return EXEC_DEFAULT; }
float __stdcall calcMagicMirrorResist(HiHook* h, _BattleMgr_* battleMgr, int spell, int side, _BattleStackEx_* stack, int a5, int a6, int a7) { float magicVulnerability = CALL_7(float, __thiscall, h->GetDefaultFunc(), o_BattleMgr, spell, side, stack, a5, a6, a7); float magicMirrorChance = stack->active_spell_duration[SPL_MAGIC_MIRROR] ? o_Spell[SPL_MAGIC_MIRROR].effect[stack->active_spells_power[SPL_MAGIC_MIRROR]] * 0.01f : 0;
return redirectedSingleCast ? (1 - magicMirrorChance) * magicVulnerability : magicVulnerability; }
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); }
int _BattleStackEx_::getMonsterSpell() { int spell = ID_NONE;
if (this) { switch (this->creature_id) { case CID_THUNDERBIRD: spell = SPL_THUNDERBOLT; 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; redirectedSingleCast = 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);
if (spell >= SPL_MAGIC_ARROW && spell <= SPL_CHAIN_LIGHTNING || spell == SPL_TITANS_LIGHTNING_BOLT) { _Hero_* attHero = o_BattleMgr->hero[o_BattleMgr->current_side]; _Hero_* defHero = o_BattleMgr->hero[1 - o_BattleMgr->current_side];
sort(stackVector.begin(), stackVector.end(), cmpExtraFightValue(spell, attHero, defHero)); stable_sort(stackVector.begin(), stackVector.end(), cmpDamageFightValue(spell, attHero, defHero)); } else { sort(stackVector.begin(), stackVector.end(), cmpFightValue(spell)); 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 && uid(gen) <= o_Spell[SPL_MAGIC_MIRROR].effect[effSchoolLevel] && spell != SPL_TELEPORT && spell != SPL_SACRIFICE) { // Проигрываем одиночную анимацию stack->playAnimation(o_Spell[SPL_MAGIC_MIRROR].animation_ix);
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 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 __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;
vector <pair<double, double>> ones; ones.resize(186);
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 extraFightValueUs = 0, extraFightValueThem = 0; double damageFightValueUs = 0, damageFightValueThem = 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)) { // Переходим к следующей области, если хотя бы один отряд в ней находится под действием заклинаний: if (stack->active_spell_duration[SPL_BLIND] || stack->active_spell_duration[SPL_STONE] || stack->active_spell_duration[SPL_PARALYZE]) { ones[hex].first = 0; goto skipArea; }
// Считаем магический урон, получаемый стеком stack int spellDamage = stack->calcMagicDamage(spell, attHero, defHero);
if (stack->side == o_BattleMgr->current_side) { ++countThem; damageFightValueThem += stack->damageFightValue(spell, spellDamage); extraFightValueThem += stack->extraFightValue(spell, spellDamage); } else { ++countUs; damageFightValueUs += stack->damageFightValue(spell, spellDamage); extraFightValueUs += stack->extraFightValue(spell, spellDamage); } }
if (i + 1 < areaSize) { int iHexNext = hex + area[i + 1]; if (isValidHex(iHexNext) && (_BattleStackEx_*)o_BattleMgr->hex[iHexNext].GetCreature() == stack) ++i; } } } }
ones[hex].first = damageFightValueThem - damageFightValueUs; ones[hex].second = extraFightValueThem - extraFightValueUs;
if (countThem + countUs > 0 && damageFightValueThem - damageFightValueUs > maxDamageFightValueDelta) { maxDamageFightValueDelta = damageFightValueThem - damageFightValueUs; bestTargetHex = hex; }
skipArea:; }
for (int i = 1; i < 186; ++i) if (maxDamageFightValueDelta > 0.0 && ones[i].first == maxDamageFightValueDelta) { if (ones[i].second > ones[bestTargetHex].second) bestTargetHex = i; }
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 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->getHitChanceFull(spell);
if (uid(gen) <= 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 (uid(gen) <= 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_THUNDERBOLT; addrHit = 0x440F03; addrSkip = 0x4412AB; break; case 0x440372: spell = SPL_BLIND; addrHit = 0x44038D; addrSkip = 0x4402AE; break; case 0x440467: spell = SPL_CURSE; addrHit = 0x440482; addrSkip = 0x4402AE; break; }
if (stack->magicMirrorLucky(spell)) { c->return_address = addrSkip;
// Если сработало Magic Mirror, отражаем обратно _BattleStackEx_* stackFoe = (_BattleStackEx_*)c->esi; if (stackFoe) { int hitChanceFoe = stackFoe->getHitChanceResist(spell);
if (uid(gen) <= hitChanceFoe) { if (spell == SPL_THUNDERBOLT) { playSound(o_Spell[SPL_MAGIC_MIRROR].wav_name); stack->playAnimation(o_Spell[SPL_MAGIC_MIRROR].animation_ix); } else { targetStack = stack; showMagicMirrorAfterAttack = true; }
c->edi = (int)stackFoe; c->return_address = addrHit; } else if (hitChanceFoe) { if (spell == SPL_THUNDERBOLT) { playSound("MagicRes.wav"); stackFoe->playAnimation(78); } else { targetStack = stackFoe; showResistAfterAttack = true; } } }
return NO_EXEC_DEFAULT; }
return EXEC_DEFAULT; }
int __stdcall playAnimForMonster(LoHook* h, HookContext* c) { if (showResistAfterAttack) { playSound("MagicRes.wav"); targetStack->playAnimation(78); showResistAfterAttack = false; }
if (showMagicMirrorAfterAttack) { playSound(o_Spell[SPL_MAGIC_MIRROR].wav_name); targetStack->playAnimation(o_Spell[SPL_MAGIC_MIRROR].animation_ix); showMagicMirrorAfterAttack = false; }
return EXEC_DEFAULT; }
int __stdcall playMagicMirrorSound(LoHook* h, HookContext* c) { playSound(o_Spell[SPL_MAGIC_MIRROR].wav_name);
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); _PI->WriteHiHook(0x5A83A0, SPLICE_, EXTENDED_, THISCALL_, calcMagicMirrorResist);
// Масскаст 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(0x440467, mirrorMonsterSpell); // Curse _PI->WriteLoHook(0x468C99, playAnimForMonster); } }
return TRUE; }
AlexSpl, потестируйте мою dll-ку с Вихрем Мерсенна. Подходит ли он нам в данном случае по seed? Прикрепил dll-ку.
- Вложения
-
- NewMagicMirror.rar
- (16.95 КБ) Скачиваний: 136
|