-
AlexSpl
имя: Александр
- Эксперт
-
- Сообщения: 5587
- Зарегистрирован: 17 сен 2010, 12:58
- Пол:
- Награды: 14
-
-
- Поблагодарили: 2185 раз.
|
AlexSpl » 17 авг 2021, 23:24
Техническая демка раздачи новых заклинаний в гильдию магов: - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "..\..\HotA\homm3.h"
Patcher* _P; PatcherInstance* _PI;
//char iniPath[MAX_PATH];
#define SPELLS_NUM 71 #define SPL_FEAR 70 _Spell_ spell[128];
int __stdcall afterInit(LoHook* h, HookContext* c) { for (int i = 0; i < SPL_FEAR; ++i) spell[i] = o_Spell[i];
spell[SPL_FEAR].type = -1; spell[SPL_FEAR].wav_name = "Fear.wav"; spell[SPL_FEAR].animation_ix = 15; spell[SPL_FEAR].flags = 0x20415; spell[SPL_FEAR].name = "Fear"; spell[SPL_FEAR].short_name = "Fear"; spell[SPL_FEAR].level = 4; spell[SPL_FEAR].school_flags = 8; spell[SPL_FEAR].mana_cost[0] = 16; spell[SPL_FEAR].mana_cost[1] = 8; spell[SPL_FEAR].mana_cost[2] = 8; spell[SPL_FEAR].mana_cost[3] = 8; spell[SPL_FEAR].eff_power = 0; spell[SPL_FEAR].effect[0] = 75; spell[SPL_FEAR].effect[1] = 75; spell[SPL_FEAR].effect[2] = 50; spell[SPL_FEAR].effect[3] = 25; spell[SPL_FEAR].chance2get_var[0] = 10; spell[SPL_FEAR].chance2get_var[1] = 10; spell[SPL_FEAR].chance2get_var[2] = 10; spell[SPL_FEAR].chance2get_var[3] = 10; spell[SPL_FEAR].chance2get_var[4] = 10; spell[SPL_FEAR].chance2get_var[5] = 10; spell[SPL_FEAR].chance2get_var[6] = 10; spell[SPL_FEAR].chance2get_var[7] = 10; spell[SPL_FEAR].chance2get_var[8] = 10; spell[SPL_FEAR].ai_value[0] = 50; spell[SPL_FEAR].ai_value[1] = 50; spell[SPL_FEAR].ai_value[2] = 50; spell[SPL_FEAR].ai_value[3] = 50; spell[SPL_FEAR].description[0] = "{Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n"; spell[SPL_FEAR].description[1] = "{Basic Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nSpell Point cost is half that of Normal Fear.\n"; spell[SPL_FEAR].description[2] = "{Advanced Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is twice that of Basic Fear.\n"; spell[SPL_FEAR].description[3] = "{Expert Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is three times that of Basic Fear.\n";
for (int i = SPL_FEAR + 1; i < SPL_FEAR + 11; ++i) spell[i] = o_Spell[i];
_PI->WriteDword(0x687FA8, (int)&spell);
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("HD.Plugin.H3.NewSpells");
//GetCurrentDirectoryA(sizeof(iniPath), iniPath); //strcat(iniPath, "\\NewSpells.ini");
_PI->WriteLoHook(0x4EE1C1, afterInit);
// Mage Guild _PI->WriteByte(0x5BEA2C, SPELLS_NUM); _PI->WriteByte(0x5BEA70, SPELLS_NUM); _PI->WriteByte(0x5BEAAD, SPELLS_NUM); _PI->WriteByte(0x5BEB48, SPELLS_NUM); _PI->WriteByte(0x5BEB71, SPELLS_NUM); _PI->WriteByte(0x5BEBB2, SPELLS_NUM); _PI->WriteByte(0x5BEC1B, SPELLS_NUM);
_PI->WriteDword(0x5BEAFE, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5BEB2C, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5BEC05, SPELLS_NUM * sizeof(_Spell_));
_PI->WriteByte(0x4E67AC, SPELLS_NUM); } }
return TRUE; }
Примечание. Версия неиграбельна (сломаны спецабилки сущетсв из-за переноса). Просто полюбоваться картинкой.
- SpellScr.zip
- Распаковать в в _H3_Data\Common
- (116.61 КБ) Скачиваний: 142
* * * Второй этап - научить героев изучать новые заклинания. Здесь я решил не переносить структуры героев в код плагина и не увеличивать их размер, т.к. структура героя в коде используется повсеместно и получится слишком много патчей. Гораздо проще объединить поля _byte_ spell[70]; // +1002 _byte_ spell_level[70]; // +1072 Это два булевых массива. В первом отмечаются заклинания, которые герой выучил, во втором - которые он может кастовать. Зачем два? Например, герой может получить заклинание из свитка или артефакта. В этом случае он может кастовать заклинание, но не знает его. Ничто не мешает использовать байт более благоразумно: 0 - герой не знает заклинание; 1 - герой знает заклинание; 2 (или -1) - герой не знает заклинание, но может его кастовать. С таким подходом мы расширяем список заклинаний до 140, что уже больше требуемых 128 (0 - 127 - положительные значения, которые может хранить char). Остаётся написать хуки, изменяющие способ работы с этими полями, а кода, который с ними работает гораздо меньше, чем того, который работает со структурой героя. WIP - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "..\..\HotA\homm3.h"
Patcher* _P; PatcherInstance* _PI;
//char iniPath[MAX_PATH];
#define SPELLS_NUM 71 #define SPL_FEAR 70 _Spell_ spell[128];
int __stdcall afterInit(LoHook* h, HookContext* c) { for (int i = 0; i < SPL_FEAR; ++i) spell[i] = o_Spell[i];
spell[SPL_FEAR].type = -1; spell[SPL_FEAR].wav_name = "Fear.wav"; spell[SPL_FEAR].animation_ix = 15; spell[SPL_FEAR].flags = 0x20415; spell[SPL_FEAR].name = "Fear"; spell[SPL_FEAR].short_name = "Fear"; spell[SPL_FEAR].level = 4; spell[SPL_FEAR].school_flags = 8; spell[SPL_FEAR].mana_cost[0] = 16; spell[SPL_FEAR].mana_cost[1] = 8; spell[SPL_FEAR].mana_cost[2] = 8; spell[SPL_FEAR].mana_cost[3] = 8; spell[SPL_FEAR].eff_power = 0; spell[SPL_FEAR].effect[0] = 75; spell[SPL_FEAR].effect[1] = 75; spell[SPL_FEAR].effect[2] = 50; spell[SPL_FEAR].effect[3] = 25; spell[SPL_FEAR].chance2get_var[0] = 10; spell[SPL_FEAR].chance2get_var[1] = 10; spell[SPL_FEAR].chance2get_var[2] = 10; spell[SPL_FEAR].chance2get_var[3] = 10; spell[SPL_FEAR].chance2get_var[4] = 10; spell[SPL_FEAR].chance2get_var[5] = 10; spell[SPL_FEAR].chance2get_var[6] = 10; spell[SPL_FEAR].chance2get_var[7] = 10; spell[SPL_FEAR].chance2get_var[8] = 10; spell[SPL_FEAR].ai_value[0] = 50; spell[SPL_FEAR].ai_value[1] = 50; spell[SPL_FEAR].ai_value[2] = 50; spell[SPL_FEAR].ai_value[3] = 50; spell[SPL_FEAR].description[0] = "{Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n"; spell[SPL_FEAR].description[1] = "{Basic Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nSpell Point cost is half that of Normal Fear.\n"; spell[SPL_FEAR].description[2] = "{Advanced Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is twice that of Basic Fear.\n"; spell[SPL_FEAR].description[3] = "{Expert Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is three times that of Basic Fear.\n";
for (int i = SPL_FEAR + 1; i < SPL_FEAR + 11; ++i) spell[i] = o_Spell[i];
_PI->WriteDword(0x687FA8, (int)&spell);
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("HD.Plugin.H3.NewSpells");
//GetCurrentDirectoryA(sizeof(iniPath), iniPath); //strcat(iniPath, "\\NewSpells.ini");
_PI->WriteLoHook(0x4EE1C1, afterInit);
// Mage Guild _PI->WriteByte(0x5BEA2C, SPELLS_NUM); _PI->WriteByte(0x5BEA70, SPELLS_NUM); _PI->WriteByte(0x5BEAAD, SPELLS_NUM); _PI->WriteByte(0x5BEB48, SPELLS_NUM); _PI->WriteByte(0x5BEB71, SPELLS_NUM); _PI->WriteByte(0x5BEBB2, SPELLS_NUM); _PI->WriteByte(0x5BEC1B, SPELLS_NUM);
_PI->WriteDword(0x5BEAFE, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5BEB2C, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5BEC05, SPELLS_NUM * sizeof(_Spell_));
_PI->WriteByte(0x4E67AC, SPELLS_NUM);
// Learning Spells _PI->WriteCodePatch(0x4D95AF, "%n", 7); _PI->WriteByte(0x402902, SPELLS_NUM); // Cheats _PI->WriteByte(0x471C57, SPELLS_NUM); // Cheats in battle _PI->WriteByte(0x427085, SPELLS_NUM); _PI->WriteByte(0x4864B0, SPELLS_NUM); _PI->WriteByte(0x48A34B, SPELLS_NUM); _PI->WriteByte(0x4F508B, SPELLS_NUM); _PI->WriteDword(0x4F50CE, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4F5114, SPELLS_NUM * sizeof(_Spell_));
_PI->WriteDword(0x59CD5E, 0x3EA); // Spell Book _PI->WriteDword(0x59CDBF, SPELLS_NUM * sizeof(_Spell_)); // Spell Book
_PI->WriteDword(0x5BE512, SPELLS_NUM * sizeof(_Spell_)); // Conflux Grail _PI->WriteDword(0x5BE56E, SPELLS_NUM * sizeof(_Spell_)); // Conflux Grail
} }
return TRUE; }
Это не все патчи. Версия для демонстрации изучения новых заклинаний. О багах писать пока не стоит * * * И версия для Rolex Вот эту неплохо бы погонять со всем, что связано с магией (крэш-логи очень нужны; они помогут найти ещё не найденный код, который требуется изменить). Только абилки не тестируйте. Я их ещё не перемещал. - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "..\..\HotA\homm3.h"
Patcher* _P; PatcherInstance* _PI;
//char iniPath[MAX_PATH];
#define SPELLS_NUM 71 #define SPL_FEAR 70 _Spell_ spell[128];
int __stdcall afterInit(LoHook* h, HookContext* c) { for (int i = 0; i < SPL_FEAR; ++i) spell[i] = o_Spell[i];
spell[SPL_FEAR].type = -1; spell[SPL_FEAR].wav_name = "Fear.wav"; spell[SPL_FEAR].animation_ix = 15; spell[SPL_FEAR].flags = 0x20415; spell[SPL_FEAR].name = "Fear"; spell[SPL_FEAR].short_name = "Fear"; spell[SPL_FEAR].level = 4; spell[SPL_FEAR].school_flags = 8; spell[SPL_FEAR].mana_cost[0] = 16; spell[SPL_FEAR].mana_cost[1] = 8; spell[SPL_FEAR].mana_cost[2] = 8; spell[SPL_FEAR].mana_cost[3] = 8; spell[SPL_FEAR].eff_power = 0; spell[SPL_FEAR].effect[0] = 75; spell[SPL_FEAR].effect[1] = 75; spell[SPL_FEAR].effect[2] = 50; spell[SPL_FEAR].effect[3] = 25; spell[SPL_FEAR].chance2get_var[0] = 10; spell[SPL_FEAR].chance2get_var[1] = 10; spell[SPL_FEAR].chance2get_var[2] = 10; spell[SPL_FEAR].chance2get_var[3] = 10; spell[SPL_FEAR].chance2get_var[4] = 10; spell[SPL_FEAR].chance2get_var[5] = 10; spell[SPL_FEAR].chance2get_var[6] = 10; spell[SPL_FEAR].chance2get_var[7] = 10; spell[SPL_FEAR].chance2get_var[8] = 10; spell[SPL_FEAR].ai_value[0] = 50; spell[SPL_FEAR].ai_value[1] = 50; spell[SPL_FEAR].ai_value[2] = 50; spell[SPL_FEAR].ai_value[3] = 50; spell[SPL_FEAR].description[0] = "{Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n"; spell[SPL_FEAR].description[1] = "{Basic Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nSpell Point cost is half that of Normal Fear.\n"; spell[SPL_FEAR].description[2] = "{Advanced Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is twice that of Basic Fear.\n"; spell[SPL_FEAR].description[3] = "{Expert Fear}\n\nStrikes an enemy unit with such fear that it becomes unable to attack and nearly unable to move.\n\nPenalty to movement is three times that of Basic Fear.\n";
for (int i = SPL_FEAR + 1; i < SPL_FEAR + 11; ++i) spell[i] = o_Spell[i];
_PI->WriteDword(0x687FA8, (int)&spell);
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("HD.Plugin.H3.NewSpells");
//GetCurrentDirectoryA(sizeof(iniPath), iniPath); //strcat(iniPath, "\\NewSpells.ini");
_PI->WriteLoHook(0x4EE1C1, afterInit);
// Mage Guild _PI->WriteByte(0x5BEA2C, SPELLS_NUM); _PI->WriteByte(0x5BEA70, SPELLS_NUM); _PI->WriteByte(0x5BEAAD, SPELLS_NUM); _PI->WriteByte(0x5BEB48, SPELLS_NUM); _PI->WriteByte(0x5BEB71, SPELLS_NUM); _PI->WriteByte(0x5BEBB2, SPELLS_NUM); _PI->WriteByte(0x5BEC1B, SPELLS_NUM);
_PI->WriteDword(0x5BEAFE, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5BEB2C, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5BEC05, SPELLS_NUM * sizeof(_Spell_));
_PI->WriteByte(0x4E67AC, SPELLS_NUM);
// Learning Spells _PI->WriteCodePatch(0x4D95AF, "%n", 7); _PI->WriteByte(0x402902, SPELLS_NUM); // Cheats _PI->WriteByte(0x471C57, SPELLS_NUM); // Cheats in battle _PI->WriteByte(0x427085, SPELLS_NUM); _PI->WriteByte(0x4864B0, SPELLS_NUM); _PI->WriteByte(0x48A34B, SPELLS_NUM); _PI->WriteByte(0x4F508B, SPELLS_NUM); _PI->WriteDword(0x4F50CE, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4F5114, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x59CD5E, 0x3EA); // Spell Book _PI->WriteDword(0x59CDBF, SPELLS_NUM * sizeof(_Spell_)); // Spell Book
// Conflux Grail _PI->WriteDword(0x5BE512, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5BE56E, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x5D7464, SPELLS_NUM);
// WIP _PI->WriteDword(0x425E98, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4329C1, 0x3EA); _PI->WriteDword(0x432A43, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x432CDE, 0x3EA); _PI->WriteDword(0x432D1E, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x43C21B, SPELLS_NUM * sizeof(_Spell_)); // Master Genie AI _PI->WriteDword(0x43C6F2, SPELLS_NUM * sizeof(_Spell_)); // Battle AI _PI->WriteDword(0x447551, SPELLS_NUM * sizeof(_Spell_)); // Casters _PI->WriteDword(0x4C24C9, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteByte(0x4C250E, SPELLS_NUM); _PI->WriteDword(0x4C2557, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4C260D, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4C92C5, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4C9347, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4C93C0, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4D962D, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4D9681, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4D96D6, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4D972E, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x4D9771, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x527ACB, 0x3EA); _PI->WriteDword(0x527B08, SPELLS_NUM * sizeof(_Spell_)); _PI->WriteDword(0x52A97A, 0x3EA); // AI _PI->WriteDword(0x52A9B6, SPELLS_NUM * sizeof(_Spell_)); // AI _PI->WriteDword(0x534C4B, SPELLS_NUM * sizeof(_Spell_)); // RMG _PI->WriteDword(0x5A1AD6, SPELLS_NUM * sizeof(_Spell_)); // Cast Spell
_PI->WriteByte(0x4C244D, SPELLS_NUM); _PI->WriteByte(0x4C246F, SPELLS_NUM); _PI->WriteByte(0x4CEC4F, SPELLS_NUM); } }
return TRUE; }
|