-
Ben80
имя: Сергей
- Эксперт
-
- Сообщения: 1318
- Зарегистрирован: 18 июн 2017, 06:49
- Пол:
- Поблагодарили: 336 раз.
|
Ben80 » 08 окт 2017, 13:27
Вот такой код в итоге получается: Русская версия: Код - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "..\..\include\homm3.h"
Patcher* _P; PatcherInstance* _PI;
static _bool_ plugin_On = 0;
const int ghostHeroHookAddr[] = {0x41664C, 0x4DE583, 0x5D44A0, 0x5D451D}; _Hero_* ghostHero = new _Hero_(); _Hero_* curHero;
int nPos, s_ebx, s_edx;;
struct disguiseStruct { char duration : 4; char index : 4; char unusedByte; short unusedWord; } *disguise;
float getDisguiseMultiplier(int n) { float multiplier[] = {1.0f, 1.5f, 2.0f, 3.0f, 5.0f}; return n >= 0 ? multiplier[n] : 1.0f / multiplier[-n - 1]; }
void getArmyCountText(const _Hero_* hero, const int stackId, const int index = 0) { sprintf(o_TextBuffer, "%s", ""); if ( hero->army.type[stackId] > ID_NONE ) { int armyCount = (int)(getDisguiseMultiplier(index) * hero->army.count[stackId]); // Спасаем единички if ( armyCount < 1 ) armyCount = 1; if ( armyCount < 10000 ) sprintf(o_TextBuffer, "%d", armyCount); else sprintf(o_TextBuffer, "%dk", armyCount / 1000); } }
// Создаём стандартный задник с рамкой цвета игрока void setStdBackground(_Dlg_* dlg) { CALL_5(int, __thiscall, 0x48FA80, dlg, dlg->x, dlg->y, dlg->width, dlg->height);
for (_ptr_ i = dlg->field_4C; i <= dlg->field_50; ++i) { CALL_5(int, __thiscall, 0x5FF400, dlg, 512, 13, i, o_GameMgr->GetMeID()); } }
void __fastcall scrollDlgCallback(int click_id, _Dlg_* dlg) { nPos = click_id - ((_DlgScroll_*)dlg->GetItem(40))->ticks_count / 2; if ( nPos < 0 ) --nPos; float multiplier = getDisguiseMultiplier(nPos); char Text[10]; sprintf(Text, "%d%s", (int)(multiplier * 100), "%");
((_DlgStaticText_*)dlg->GetItem(14))->SetText(Text);
for (int i = 0; i < 7; ++i) { getArmyCountText(curHero, i, nPos); ((_DlgStaticText_*)dlg->GetItem(20 + i))->SetText(o_TextBuffer); }
// Устанавливаем ползунок в ближайшее к точке клика положение _DlgMsg_ m = {512, 3, 40, 0, 0, 0, 0, 0}; CALL_2(void, __thiscall, 0x5FF3A0, dlg, &m); dlg->Redraw(TRUE); }
void yDlgShow(int width, int height, int count, char* captionText, char* messageText, bool middle = true, int x = 0, int y = 0) { // Создаём по центру экрана пустой диалог с тенью _Dlg_* dlg = _CustomDlg_::Create(DLG_X_CENTER, DLG_Y_CENTER, width, height, DF_SCREENSHOT | DF_SHADOW, NULL); // Добавляем задник (фон) и рамку по цвету игрока setStdBackground(dlg);
// Добавляем заголовок диалога dlg->AddItem(_DlgStaticText_::Create(0, 24, dlg->width, 30, captionText, "bigfont.fnt", 7, 1, ALIGN_H_CENTER | ALIGN_V_TOP, 0));
// Добавляем текст dlg->AddItem(_DlgStaticText_::Create(0, 54, dlg->width, 50, messageText, "medfont.fnt", 1, 0, ALIGN_H_CENTER | ALIGN_V_TOP, 0));
// Добавляем иконки армии и численность for (int i = 0; i < 7; ++i) { int armyTypeId = ID_NONE; if ( curHero->army.type[i] > ID_NONE ) armyTypeId = curHero->army.type[i] + 2;
int leftX = (dlg->width - 236) / 2; // Добавляем тёмный фон для иконок dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 0, "cprsmall.def", 0, 0, 0)); // Добавляем иконки армии if ( armyTypeId > ID_NONE ) { dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 30 + i, "cprsmall.def", armyTypeId, 0, 0)); } // Добавляем рамку для иконок dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 0, "cprsmall.def", 1, 0, 0)); // Добавляем надписи с численностью отрядов getArmyCountText(curHero, i); dlg->AddItem(_DlgStaticText_::Create(leftX + 1 + i * 34, 144, 32, 16, o_TextBuffer, "tiny.fnt", 1, 20 + i, ALIGN_H_CENTER | ALIGN_V_TOP, 0));
}
// Добавляем полосу горизонтальной прокрутки и устанавливаем ползунок по центру _DlgScroll_* disguiseScroll = _DlgScroll_::Create(30, dlg->height - 90, dlg->width - 30 * 2 + 1, 16, 40, count, (_ptr_)scrollDlgCallback, 0, 0, 0); disguiseScroll->tick = count / 2; disguiseScroll->tick_value = count / 2; disguiseScroll->btn_position = (disguiseScroll->width - disguiseScroll->btn_size2) / 2; dlg->AddItem(disguiseScroll); // Добавляем текстовое поле для отображения значений, выбираемых с помощью ползунка dlg->AddItem(_DlgStaticText_::Create((dlg->width - 72) / 2 + 1, dlg->height - 65, 72, 40, "100%", "medfont.fnt", 1, 14, ALIGN_H_CENTER | ALIGN_V_CENTER, 0));
// Добавляем кнопку OK dlg->AddItem(_DlgStaticPcx8_::Create(30, dlg->height - 61, 0, "Box64x30.pcx")); dlg->AddItem(_DlgButton_::Create(31, dlg->height - 60, 64, 30, 30722, "iOkay.def", 0, 1, 1, 28, 2));
// Добавляем кнопку Cancel dlg->AddItem(_DlgStaticPcx8_::Create(dlg->width - 31 - 64, dlg->height - 61, 0, "Box64x30.pcx")); dlg->AddItem(_DlgButton_::Create(dlg->width - 30 - 64, dlg->height - 60, 64, 30, 30721, "iCancel.def", 0, 1, 1, 1, 2));
if ( !middle ) dlg->SetPos(x, y); dlg->Run(); dlg->Destroy(TRUE); }
int __stdcall makeGhostHero(LoHook* h, HookContext* c) { _Hero_* hero; int* heroReg;
h->GetAddress() == ghostHeroHookAddr[0] ? heroReg = &c->esi : heroReg = &c->eax; hero = *(_Hero_**)heroReg; disguise = (disguiseStruct*)&hero->disguise;
if ( hero->disguise != -1 ) { // Копируем героя в "призрачного" героя *ghostHero = *hero; ghostHero->disguise = -1;
for (int i = 0; i < 7; ++i) { if ( hero->army.type[i] > ID_NONE ) { ghostHero->army.count[i] = (int)(getDisguiseMultiplier(disguise->index) * ghostHero->army.count[i]);
// Спасаем единички if ( ghostHero->army.count[i] < 1 ) ghostHero->army.count[i] = 1; } } *(int*)heroReg = (int)ghostHero; }
return EXEC_DEFAULT; }
int __stdcall newDay(LoHook* h, HookContext* c) { for (int i = 0; i < o_HEROES_COUNT; ++i) { disguise = (disguiseStruct*)&o_GameMgr->GetHero(i)->disguise; if ( disguise->duration == -1 ) o_GameMgr->GetHero(i)->disguise = -1; } return EXEC_DEFAULT; }
int __stdcall decDisguise(LoHook* h, HookContext* c) { for (int i = 0; i < o_HEROES_COUNT; ++i) { if ( o_ActivePlayer->IsHuman() && o_GameMgr->GetHero(i)->owner_id == o_GameMgr->GetMeID() ) { disguise = (disguiseStruct*)&o_GameMgr->GetHero(i)->disguise; if ( disguise->duration != -1 ) --disguise->duration; } }
return EXEC_DEFAULT; }
int __stdcall setDisguise(LoHook* h, HookContext* c) { nPos = 0; _Hero_* hero = (_Hero_*)c->esi; curHero = hero;
// Показываем диалог с горизонтальной полосой прокрутки на 3/5/9 значений // для Базового/Продвинутого/Экспертного навыка int count[4] = {3,3,5,9}; char Text[100]; sprintf(Text, "{%s}, выберите мнимую\nсилу армии", hero->name); yDlgShow(320, 256, count[hero->second_skill[HSS_AIR_MAGIC]], "{Маскировка}", Text);
bool disguiseCast = o_WndMgr->result_dlg_item_id == 30722;
// Индекс множителя маскировки помещаем в старший полубайт, // длительность "Маскировки" (2 хода) - в младший if ( disguiseCast ) { disguise = (disguiseStruct*)&hero->disguise; disguise->index = nPos; disguise->duration = 1;
// Расходуем ману CALL_2(int, __thiscall, 0x4D9540, hero, c->eax);
// Проигрываем звук Disguise CALL_1(void, __thiscall, 0x59A770, *(int*)(*(int*)0x687FA8 + 548)); // Выполняем функцию, параметры для которой вернула функция воспроизведения WAV CALL_3(void, __thiscall, 0x59A7C0, -1, s_ebx, s_edx); } c->return_address = 0x41C7F2; return NO_EXEC_DEFAULT; }
int __stdcall saveRegs(LoHook* h, HookContext* c) { s_ebx = c->ebx; s_edx = c->edx; return EXEC_DEFAULT; }
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if ( DLL_PROCESS_ATTACH == ul_reason_for_call ) { if ( !plugin_On ) { plugin_On = 1; _P = GetPatcher(); _PI = _P->CreateInstance("HD.Plugin.NewDisguise");
_PI->WriteCodePatch(0x4C7DA5, "%n", 3); _PI->WriteCodePatch(0x41C7C6, "%n", 6); _PI->WriteCodePatch(0x41C7BA, "%n", 5); _PI->WriteLoHook(0x41C7CC, saveRegs); _PI->WriteLoHook(0x41C7DD, setDisguise); _PI->WriteLoHook(0x4C6CA9, decDisguise); _PI->WriteLoHook(0x4C7CA0, newDay); for (int i = 0; i < 4; ++i) _PI->WriteLoHook(ghostHeroHookAddr[i], makeGhostHero); } }
return TRUE; }
Английская версия: Код - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "..\..\include\homm3.h"
Patcher* _P; PatcherInstance* _PI;
static _bool_ plugin_On = 0;
const int ghostHeroHookAddr[] = {0x41664C, 0x4DE583, 0x5D44A0, 0x5D451D}; _Hero_* ghostHero = new _Hero_(); _Hero_* curHero;
int nPos, s_ebx, s_edx;;
struct disguiseStruct { char duration : 4; char index : 4; char unusedByte; short unusedWord; } *disguise;
float getDisguiseMultiplier(int n) { float multiplier[] = {1.0f, 1.5f, 2.0f, 3.0f, 5.0f}; return n >= 0 ? multiplier[n] : 1.0f / multiplier[-n - 1]; }
void getArmyCountText(const _Hero_* hero, const int stackId, const int index = 0) { sprintf(o_TextBuffer, "%s", ""); if ( hero->army.type[stackId] > ID_NONE ) { int armyCount = (int)(getDisguiseMultiplier(index) * hero->army.count[stackId]); // Спасаем единички if ( armyCount < 1 ) armyCount = 1; if ( armyCount < 10000 ) sprintf(o_TextBuffer, "%d", armyCount); else sprintf(o_TextBuffer, "%dk", armyCount / 1000); } }
// Создаём стандартный задник с рамкой цвета игрока void setStdBackground(_Dlg_* dlg) { CALL_5(int, __thiscall, 0x48FA80, dlg, dlg->x, dlg->y, dlg->width, dlg->height);
for (_ptr_ i = dlg->field_4C; i <= dlg->field_50; ++i) { CALL_5(int, __thiscall, 0x5FF400, dlg, 512, 13, i, o_GameMgr->GetMeID()); } }
void __fastcall scrollDlgCallback(int click_id, _Dlg_* dlg) { nPos = click_id - ((_DlgScroll_*)dlg->GetItem(40))->ticks_count / 2; if ( nPos < 0 ) --nPos; float multiplier = getDisguiseMultiplier(nPos); char Text[10]; sprintf(Text, "%d%s", (int)(multiplier * 100), "%");
((_DlgStaticText_*)dlg->GetItem(14))->SetText(Text);
for (int i = 0; i < 7; ++i) { getArmyCountText(curHero, i, nPos); ((_DlgStaticText_*)dlg->GetItem(20 + i))->SetText(o_TextBuffer); }
// Устанавливаем ползунок в ближайшее к точке клика положение _DlgMsg_ m = {512, 3, 40, 0, 0, 0, 0, 0}; CALL_2(void, __thiscall, 0x5FF3A0, dlg, &m); dlg->Redraw(TRUE); }
void yDlgShow(int width, int height, int count, char* captionText, char* messageText, bool middle = true, int x = 0, int y = 0) { // Создаём по центру экрана пустой диалог с тенью _Dlg_* dlg = _CustomDlg_::Create(DLG_X_CENTER, DLG_Y_CENTER, width, height, DF_SCREENSHOT | DF_SHADOW, NULL); // Добавляем задник (фон) и рамку по цвету игрока setStdBackground(dlg);
// Добавляем заголовок диалога dlg->AddItem(_DlgStaticText_::Create(0, 24, dlg->width, 30, captionText, "bigfont.fnt", 7, 1, ALIGN_H_CENTER | ALIGN_V_TOP, 0));
// Добавляем текст dlg->AddItem(_DlgStaticText_::Create(0, 54, dlg->width, 50, messageText, "medfont.fnt", 1, 0, ALIGN_H_CENTER | ALIGN_V_TOP, 0));
// Добавляем иконки армии и численность for (int i = 0; i < 7; ++i) { int armyTypeId = ID_NONE; if ( curHero->army.type[i] > ID_NONE ) armyTypeId = curHero->army.type[i] + 2;
int leftX = (dlg->width - 236) / 2; // Добавляем тёмный фон для иконок dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 0, "cprsmall.def", 0, 0, 0)); // Добавляем иконки армии if ( armyTypeId > ID_NONE ) { dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 30 + i, "cprsmall.def", armyTypeId, 0, 0)); } // Добавляем рамку для иконок dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 0, "cprsmall.def", 1, 0, 0)); // Добавляем надписи с численностью отрядов getArmyCountText(curHero, i); dlg->AddItem(_DlgStaticText_::Create(leftX + 1 + i * 34, 144, 32, 16, o_TextBuffer, "tiny.fnt", 1, 20 + i, ALIGN_H_CENTER | ALIGN_V_TOP, 0));
}
// Добавляем полосу горизонтальной прокрутки и устанавливаем ползунок по центру _DlgScroll_* disguiseScroll = _DlgScroll_::Create(30, dlg->height - 90, dlg->width - 30 * 2 + 1, 16, 40, count, (_ptr_)scrollDlgCallback, 0, 0, 0); disguiseScroll->tick = count / 2; disguiseScroll->tick_value = count / 2; disguiseScroll->btn_position = (disguiseScroll->width - disguiseScroll->btn_size2) / 2; dlg->AddItem(disguiseScroll); // Добавляем текстовое поле для отображения значений, выбираемых с помощью ползунка dlg->AddItem(_DlgStaticText_::Create((dlg->width - 72) / 2 + 1, dlg->height - 65, 72, 40, "100%", "medfont.fnt", 1, 14, ALIGN_H_CENTER | ALIGN_V_CENTER, 0));
// Добавляем кнопку OK dlg->AddItem(_DlgStaticPcx8_::Create(30, dlg->height - 61, 0, "Box64x30.pcx")); dlg->AddItem(_DlgButton_::Create(31, dlg->height - 60, 64, 30, 30722, "iOkay.def", 0, 1, 1, 28, 2));
// Добавляем кнопку Cancel dlg->AddItem(_DlgStaticPcx8_::Create(dlg->width - 31 - 64, dlg->height - 61, 0, "Box64x30.pcx")); dlg->AddItem(_DlgButton_::Create(dlg->width - 30 - 64, dlg->height - 60, 64, 30, 30721, "iCancel.def", 0, 1, 1, 1, 2));
if ( !middle ) dlg->SetPos(x, y); dlg->Run(); dlg->Destroy(TRUE); }
int __stdcall makeGhostHero(LoHook* h, HookContext* c) { _Hero_* hero; int* heroReg;
h->GetAddress() == ghostHeroHookAddr[0] ? heroReg = &c->esi : heroReg = &c->eax; hero = *(_Hero_**)heroReg; disguise = (disguiseStruct*)&hero->disguise;
if ( hero->disguise != -1 ) { // Копируем героя в "призрачного" героя *ghostHero = *hero; ghostHero->disguise = -1;
for (int i = 0; i < 7; ++i) { if ( hero->army.type[i] > ID_NONE ) { ghostHero->army.count[i] = (int)(getDisguiseMultiplier(disguise->index) * ghostHero->army.count[i]);
// Спасаем единички if ( ghostHero->army.count[i] < 1 ) ghostHero->army.count[i] = 1; } } *(int*)heroReg = (int)ghostHero; }
return EXEC_DEFAULT; }
int __stdcall newDay(LoHook* h, HookContext* c) { for (int i = 0; i < o_HEROES_COUNT; ++i) { disguise = (disguiseStruct*)&o_GameMgr->GetHero(i)->disguise; if ( disguise->duration == -1 ) o_GameMgr->GetHero(i)->disguise = -1; } return EXEC_DEFAULT; }
int __stdcall decDisguise(LoHook* h, HookContext* c) { for (int i = 0; i < o_HEROES_COUNT; ++i) { if ( o_ActivePlayer->IsHuman() && o_GameMgr->GetHero(i)->owner_id == o_GameMgr->GetMeID() ) { disguise = (disguiseStruct*)&o_GameMgr->GetHero(i)->disguise; if ( disguise->duration != -1 ) --disguise->duration; } }
return EXEC_DEFAULT; }
int __stdcall setDisguise(LoHook* h, HookContext* c) { nPos = 0; _Hero_* hero = (_Hero_*)c->esi; curHero = hero;
// Показываем диалог с горизонтальной полосой прокрутки на 3/5/9 значений // для Базового/Продвинутого/Экспертного навыка int count[4] = {3,3,5,9}; char Text[100]; sprintf(Text, "{%s}, select falsified\narmy strength", hero->name); yDlgShow(320, 256, count[hero->second_skill[HSS_AIR_MAGIC]], "{Disguise}", Text);
bool disguiseCast = o_WndMgr->result_dlg_item_id == 30722;
// Индекс множителя маскировки помещаем в старший полубайт, // длительность "Маскировки" (2 хода) - в младший if ( disguiseCast ) { disguise = (disguiseStruct*)&hero->disguise; disguise->index = nPos; disguise->duration = 1;
// Расходуем ману CALL_2(int, __thiscall, 0x4D9540, hero, c->eax);
// Проигрываем звук Disguise CALL_1(void, __thiscall, 0x59A770, *(int*)(*(int*)0x687FA8 + 548)); // Выполняем функцию, параметры для которой вернула функция воспроизведения WAV CALL_3(void, __thiscall, 0x59A7C0, -1, s_ebx, s_edx); } c->return_address = 0x41C7F2; return NO_EXEC_DEFAULT; }
int __stdcall saveRegs(LoHook* h, HookContext* c) { s_ebx = c->ebx; s_edx = c->edx; return EXEC_DEFAULT; }
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if ( DLL_PROCESS_ATTACH == ul_reason_for_call ) { if ( !plugin_On ) { plugin_On = 1; _P = GetPatcher(); _PI = _P->CreateInstance("HD.Plugin.NewDisguise");
_PI->WriteCodePatch(0x4C7DA5, "%n", 3); _PI->WriteCodePatch(0x41C7C6, "%n", 6); _PI->WriteCodePatch(0x41C7BA, "%n", 5); _PI->WriteLoHook(0x41C7CC, saveRegs); _PI->WriteLoHook(0x41C7DD, setDisguise); _PI->WriteLoHook(0x4C6CA9, decDisguise); _PI->WriteLoHook(0x4C7CA0, newDay); for (int i = 0; i < 4; ++i) _PI->WriteLoHook(ghostHeroHookAddr[i], makeGhostHero); } }
return TRUE; }
Последний раз редактировалось Ben80 08 окт 2017, 15:38, всего редактировалось 6 раз(а).
|