Название: FairCancelSpells
Описание: Заклинания Dispel и Cure снимают только последнее наложенное заклинание/эффект. В случае, если последнее заклинание/эффект невозможно снять (например, последний эффект - Poison для Dispel или какой-нибудь баф для Cure), снимается ближайшее заклинание/эффект, которое можно снять.
- Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0
#pragma warning(disable : 4005)
#pragma warning(disable : 4010)
#include "stdafx.h"
#include <vector>
#include "..\..\HotA\homm3.h"
Patcher* _P;
PatcherInstance* _PI;
#pragma pack(push, 4)
class stdDequeIterator {
public:
int* first;
int* last;
int* node;
int** map;
};
class stdDeque {
public:
char allocator;
stdDequeIterator itFirst;
stdDequeIterator itLast;
int** map;
int mapSize;
int size;
};
struct SLimitData
{
int MinX;
int MinY;
int MaxX;
int MaxY;
};
struct TObstacleInfo
{
unsigned long backgroundMask;
unsigned char height;
unsigned char width;
unsigned char numSquares;
unsigned char underlay;
char sOffsets[8];
const char* FileName;
};
// Actual types are commented, as we don't need them in this plugin
struct TObstacle
{
// CSprite* sprite;
int* sprite;
TObstacleInfo* info;
unsigned char grid_index;
char owner;
bool is_visible;
int damage;
int duration;
// TSpellEffectID dispel_effect;
int dispel_effect;
};
class hexcell {
public:
short refX;
short refY;
short hexULX;
short hexULY;
short hexBRX;
short hexBRY;
short fullHexBRY;
unsigned int attributes;
int obstacleIndex;
char armyGrp;
char armyIndex;
char partOfDouble;
int iBodiesInHex;
char deadArmyGrp[14];
char deadArmyIndex[14];
char deadPartOfDouble[14];
bool bValidMove;
unsigned char front_move;
unsigned char mouse_shaded;
char background_offset;
SLimitData obstacleLimitData;
SLimitData cloudLimitData;
};
#pragma pack(pop)
class army : public _BattleStack_ {
public:
inline void CancelIndividualSpell(int SpellID) {
CALL_2(void, __thiscall, 0x444230, this, SpellID);
}
};
void debugStrWin(const char* format, ...)
{
va_list args;
va_start(args, format);
vsprintf(o_TextBuffer, format, args);
ShowMessage(o_TextBuffer);
va_end(args);
}
#define SPL_DISPEL 35
#define SPL_STONE_GAZE 70
#define SPL_DISEASE 73
#define SPL_AGE 75
#define SPL_DISPEL_HELPFUL_SPELLS 78
int __stdcall fixCure(LoHook* h, HookContext* c)
{
army* Army = (army*)c->esi;
Army->lost_hp = c->eax;
if (Army->active_spells_count)
{
stdDeque* spellDeque = (stdDeque*)(c->esi + 0x420);
for (int i = spellDeque->size; i > 0; --i)
{
// You can do so because the size of spellDeque's chunk is 4096 bytes,
// and this is more than enough for all possible spells
int spell = spellDeque->itFirst.node[i - 1];
if (spell == SPL_CURSE || spell == SPL_WEAKNESS || spell == SPL_SORROW || spell == SPL_MISFORTUNE ||
spell == SPL_SLOW || spell == SPL_BERSERK || spell == SPL_HYPNOTIZE || spell == SPL_FORGETFULNESS ||
spell == SPL_BLIND || spell == SPL_STONE_GAZE || spell == SPL_POISON || spell == SPL_DISEASE ||
spell == SPL_PARALYZE || spell == SPL_AGE)
{
Army->CancelIndividualSpell(spell);
break;
}
}
}
c->return_address = 0x4462FD;
return NO_EXEC_DEFAULT;
}
int __stdcall spellCastWorkChance(LoHook* h, HookContext* c)
{
army* Army = *(army**)(c->ebp + 0x10);
int spell = *(int*)(c->ebp + 8);
if (spell == SPL_DISPEL && Army && Army->active_spells_count)
{
stdDeque* spellDeque = (stdDeque*)(c->edi + 0x420);
for (int i = spellDeque->size; i > 0; --i)
{
int spell = spellDeque->itFirst.node[i - 1];
if (spell != SPL_POISON)
return EXEC_DEFAULT;
}
std::vector<TObstacle>* Obstacles = o_BattleMgr->PField<std::vector<TObstacle>>(0x13D58);
for (std::vector<TObstacle>::iterator it = Obstacles->begin(); it != Obstacles->end(); ++it)
if (o_BattleMgr->PField<hexcell>(0x1C4)[it->grid_index].attributes & 0x3C)
return EXEC_DEFAULT;
c->return_address = 0x5A849A;
return NO_EXEC_DEFAULT;
}
return EXEC_DEFAULT;
}
int __stdcall fixDispel(LoHook* h, HookContext* c)
{
army* Army = (army*)c->edi;
if (Army->active_spells_count)
{
stdDeque* spellDeque = (stdDeque*)(c->edi + 0x420);
for (int i = spellDeque->size; i > 0; --i)
{
int spell = spellDeque->itFirst.node[i - 1];
if (spell != SPL_POISON)
{
Army->CancelIndividualSpell(spell);
break;
}
}
}
c->return_address = 0x5A190A;
return NO_EXEC_DEFAULT;
}
int __stdcall fixMassDispel(LoHook* h, HookContext* c)
{
army* Army = (army*)c->esi;
if (Army->active_spells_count)
{
stdDeque* spellDeque = (stdDeque*)(c->esi + 0x420);
for (int i = spellDeque->size; i > 0; --i)
{
int spell = spellDeque->itFirst.node[i - 1];
if (spell != SPL_POISON)
{
Army->CancelIndividualSpell(spell);
break;
}
}
}
c->return_address = 0x5A1998;
return NO_EXEC_DEFAULT;
}
int __stdcall fixDispelHelpful(LoHook* h, HookContext* c)
{
army* Army = (army*)c->edi;
if (Army->active_spells_count)
{
stdDeque* spellDeque = (stdDeque*)(c->edi + 0x420);
for (int i = spellDeque->size; i > 0; --i)
{
int spell = spellDeque->itFirst.node[i - 1];
if (o_Spell[spell].type > 0)
{
Army->CancelIndividualSpell(spell);
break;
}
}
}
c->return_address = 0x5A1AE2;
return NO_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.H3.FairCancelSpells");
_PI->WriteLoHook(0x44627C, fixCure);
_PI->WriteLoHook(0x5A18F7, fixDispel);
_PI->WriteLoHook(0x5A1985, fixMassDispel);
_PI->WriteLoHook(0x5A1A8E, fixDispelHelpful);
_PI->WriteLoHook(0x5A8477, spellCastWorkChance);
// TODO: fixCancelValue
}
}
return TRUE;
}
FairCancelSpells.zip
- (3.8 КБ) Скачиваний: 280