-
AlexSpl
имя: Александр
- Эксперт
-
- Сообщения: 5587
- Зарегистрирован: 17 сен 2010, 12:58
- Пол:
- Награды: 14
-
-
- Поблагодарили: 2185 раз.
|
AlexSpl » 11 окт 2017, 11:31
Переделал код. Спасибо за примеры. - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "HotA\homm3.h"
Patcher* _P; PatcherInstance* _PI;
static _bool_ plugin_On = 0;
_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); // Добавляем заголовок диалога 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); }
_Dlg_* __stdcall makeGhostHero(HiHook* hook, _Dlg_* dlg, _Hero_* hero, int a3) { 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; } } hero = ghostHero; } return CALL_3(_Dlg_*, __thiscall, hook->GetDefaultFunc(), dlg, hero, a3); }
int getNextActivePlayerID() { int PlayerIDByOrder[9]; int n = 0; for (int i = 0; i < 8; ++i) { if ( o_GameMgr->IsPlayerIngame(i) && o_GameMgr->GetPlayer(i)->IsHuman() ) PlayerIDByOrder[n++] = i; }
for (int i = 0; i < 8; ++i) { if ( o_GameMgr->IsPlayerIngame(i) && !o_GameMgr->GetPlayer(i)->IsHuman() ) PlayerIDByOrder[n++] = i; } PlayerIDByOrder[n] = PlayerIDByOrder[0];
int nextActivePlayerID; for (int i = 0; i < 8; ++i) { if ( o_ActivePlayerID == PlayerIDByOrder[i] ) { nextActivePlayerID = PlayerIDByOrder[i + 1]; break; } }
return nextActivePlayerID; }
int __stdcall decDisguise(LoHook* h, HookContext* c) { int nextActivePlayerID = getNextActivePlayerID();
for (int i = 0; i < o_HEROES_COUNT; ++i) { if ( o_GameMgr->GetHero(i)->owner_id == nextActivePlayerID ) { 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\nvisible strength.", 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 хода, а для последнего игрока-человека - 3, если после него ходят компы) 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, o_Spell[SPL_DISGUISE].wav_name); // Выполняем функцию, параметры для которой вернула функция воспроизведения 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->WriteHiHook(0x52EFB0, SPLICE_, EXTENDED_, THISCALL_, makeGhostHero); } }
return TRUE; }
Осталось только разобраться, как вернуть параметры из этой функции: - Код: Выделить всё
// Проигрываем звук Disguise CALL_1(void /* struct _RTL_CRITICAL_SECTION* ??? */, __thiscall, 0x59A770, o_Spell[SPL_DISGUISE].wav_name);
в эту: - Код: Выделить всё
CALL_3(void, __thiscall, 0x59A7C0, -1, s_ebx, s_edx);
* * * - Код: Выделить всё
typedef struct _RTL_CRITICAL_SECTION { PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
// // The following three fields control entering and exiting the critical // section for the resource //
LONG LockCount; LONG RecursionCount; HANDLE OwningThread; // from the thread's ClientId->UniqueThread HANDLE LockSemaphore; ULONG_PTR SpinCount; // force size on 64-bit systems when packed } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
- Код: Выделить всё
// Проигрываем звук Disguise PRTL_CRITICAL_SECTION pCriticalSection = CALL_1(PRTL_CRITICAL_SECTION, __thiscall, 0x59A770, o_Spell[SPL_DISGUISE].wav_name); // Выполняем функцию, параметры для которой вернула функция воспроизведения WAV CALL_3(void, __thiscall, 0x59A7C0, -1, s_ebx, s_edx);
Какие именно поля структуры _RTL_CRITICAL_SECTION (если, конечно, декомпилятор прав) получает в качестве аргументов эта функция? * * * Так, вроде разобрался. Указатель на критическую секцию там или нет, но результат возвращается в паре регистров eax:edx, а значит, это так или иначе __int64.
Последний раз редактировалось AlexSpl 11 окт 2017, 12:29, всего редактировалось 1 раз.
|