-
AlexSpl
имя: Александр
- Эксперт
-
- Сообщения: 5587
- Зарегистрирован: 17 сен 2010, 12:58
- Пол:
- Награды: 14
-
-
- Поблагодарили: 2185 раз.
|
AlexSpl » 08 окт 2017, 19:17
Нет, пока в хотсите. Работает. Удивительно просто. - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "HotA\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; dlg->GetItem(30722)->SetEnabled(nPos != 0); if ( nPos < 0 ) --nPos; float multiplier = getDisguiseMultiplier(nPos); sprintf(o_TextBuffer, "%d%s", (int)(multiplier * 100), "%");
((_DlgStaticText_*)dlg->GetItem(14))->SetText(o_TextBuffer);
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);
// char Text[100]; // sprintf(Text, "%d %d -> %d %d", width, height, dlg->width, dlg->height); // b_MsgBox(Text, MBX_OK); // Добавляем заголовок диалога 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)); dlg->GetItem(30722)->SetEnabled(0);
// Добавляем кнопку 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;
// char Text[100]; // sprintf(Text, "%08X %08X", &hero->disguise, hero->disguise); // b_MsgBox(Text, MBX_OK);
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) { int activeHumanPlayersCount = 0; for (int i = 0; i < 8; ++i) { if ( o_GameMgr->PlayerIsInGameHuman(i) ) ++activeHumanPlayersCount; }
for (int i = 0; i < o_HEROES_COUNT; ++i) { if ( o_ActivePlayer->IsHuman() ) { int prevPlayer = (o_GameMgr->GetMeID() + 1) % activeHumanPlayersCount; if ( o_GameMgr->GetHero(i)->owner_id == prevPlayer ) { disguise = (disguiseStruct*)&o_GameMgr->GetHero(i)->disguise; if ( disguise->duration != -1 ) { if ( --disguise->duration == -1 ) o_GameMgr->GetHero(i)->disguise = -1; } } } }
return EXEC_DEFAULT; }
int __stdcall setDisguise(LoHook* h, HookContext* c) { nPos = 0; _Hero_* hero = (_Hero_*)c->esi; curHero = hero;
// Показываем диалог с горизонтальной полосой прокрутки // на 3/3/5/9 значений для Основного/Базового/Продвинутого/Экспертного навыка sprintf(o_TextBuffer, "{%s}, select your army\nstrength modifier.", hero->name); int tickCount[] = {3, 3, 5, 9}; yDlgShow(320, 256, tickCount[hero->second_skill[HSS_AIR_MAGIC]], "{Disguise}", o_TextBuffer); 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.TestDisguise");
_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; }
* * * Так. Нужно добавить проверку на сингл с компами, когда игрок-человек 1. Хотя кто кастует Disguise при игре с компами. Тем не менее
|