-
AlexSpl
имя: Александр
- Эксперт
-
- Сообщения: 5547
- Зарегистрирован: 17 сен 2010, 12:58
- Пол:
- Награды: 14
-
-
- Поблагодарили: 2162 раз.
|
AlexSpl » 11 окт 2017, 20:31
К этому всё идёт. * * * Перенёс хук decDisguise на 4C6FF7h. Теперь каждый игрок непосредственно перед своим ходом уменьшает длительность Disguise для своих героев. - Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS #include "HotA\homm3.h"
Patcher* _P; PatcherInstance* _PI;
static _bool_ plugin_On = 0;
int nPos; _Hero_* ghostHero = new _Hero_();
struct disguiseStruct { char duration : 4; char index : 4; char unusedByte; short unusedWord; };
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(o_GameMgr->GetHero(o_ActivePlayer->selected_hero_id), 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));
// Добавляем иконки армии и численность _Hero_* hero = o_GameMgr->GetHero(o_ActivePlayer->selected_hero_id); for (int i = 0; i < 7; ++i) { int leftX = (dlg->width - 236) / 2; // Добавляем тёмный фон для иконок dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 0, "cprsmall.def", 0, 0, 0)); // Добавляем иконки армии if ( hero->army.type[i] > ID_NONE ) { dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 30 + i, "cprsmall.def", hero->army.type[i] + 2, 0, 0)); } // Добавляем рамку для иконок dlg->AddItem(_DlgStaticDef_::Create(leftX + i * 34, 110, 0, "cprsmall.def", 1, 0, 0)); // Добавляем надписи с численностью отрядов getArmyCountText(hero, 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) { if ( hero->disguise != -1 ) { // Копируем героя в "призрачного" героя *ghostHero = *hero; disguiseStruct* disguise = (disguiseStruct*)&hero->disguise; 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 __stdcall decDisguise(LoHook* h, HookContext* c) { for (int i = 0; i < o_HEROES_COUNT; ++i) { if ( o_GameMgr->GetHero(i)->owner_id == o_ActivePlayerID ) { disguiseStruct* 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;
// Показываем диалог с горизонтальной полосой прокрутки // на 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;
// Индекс множителя маскировки помещаем в старший полубайт, // длительность "Маскировки" (1 = 2 хода) - в младший if ( disguiseCast ) { disguiseStruct* 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); CALL_3(void, __thiscall, 0x59A7C0, -1, *(int*)0x6992A8, *(int*)0x6992AC); } c->return_address = 0x41C7F2; return NO_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(0x41C7DD, setDisguise); _PI->WriteLoHook(0x4C6FF7, decDisguise); _PI->WriteHiHook(0x52EFB0, SPLICE_, EXTENDED_, THISCALL_, makeGhostHero); } }
return TRUE; }
Обновлю плагин newDisguise в теме "Пользовательские плагины" после тестов в сетевой игре.
Последний раз редактировалось AlexSpl 12 окт 2017, 20:02, всего редактировалось 1 раз.
|