-
Ben80
имя: Сергей
- Эксперт
-
- Сообщения: 1318
- Зарегистрирован: 18 июн 2017, 06:49
- Пол:
- Поблагодарили: 336 раз.
|
Ben80 » 12 окт 2017, 15:05
Авторы: AlexSpl, Ben80, igrik Название: NewDisguiseVision Описание: Меняет длительность и эффект заклинания Маскировка. Кроме того, позволяет заклинанию Видение на экспертном уровне узнавать истинную численность армии, даже если была применена Маскировка. Заклинание Видение становится заклинанием Школы воды, изменены коэффициенты для расчета расстояния, на котором действует заклинание, вместо 1/2/3 - 2/2/2. Алгоритм изменения поля disguise героя отличается от примененного в плагине NewDisguise, возможно, в сторону большей надежности. Протестирован только для SoD/Complete. С помощью диалога любой игрок может выбрать, насколько сильной армия его героя, использующего заклинание "Маскировка", будет выглядеть при просмотре этого героя игроками по правому клику. При этом информация о численности отрядов в армии героя будет искажена: преуменьшена или преувеличена. Доступны следующие опции: На основном и базовом уровне Магии Воздуха - 66%, 150% (от количества войск в каждом отряде). На продвинутом - 50%, 66%, 150%, 200%. На экспертном - 25%, 33%, 50%, 66%, 150%, 200%, 300%, 500%. Длительность заклинания - 2 хода игрока. Код - Код: Выделить всё
#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;
struct disguiseStruct { char duration : 4; char index : 4; char unusedByte; short unusedWord; } *disguise;
int __stdcall setDisguiseDescription(LoHook* h, HookContext* c) {
return EXEC_DEFAULT; }
int __stdcall setSpells(LoHook* h, HookContext* c) { // Относим заклинание Видение к Школе воды, // меняем радиус действия в зависимости от Силы магии // теперь для любого уровня Магии воды коэффициент равен 2 for(int i=0; i<4; i++) o_Spell[2].effect[i] = 2; o_Spell[2].school_flags = 4; // Меняем описание для Видения на экспертном уровне o_Spell[2].description[3] = \ "{""Виденье"" 3 уровня}\nЕсли заклинание направляется на вражеский отряд, оно сообщает точное количество войск и говорит, захотят ли они присоединиться к вам. Позволяет увидеть значения основных навыков вражеского героя и тип и количество существ в его армии, как если бы это был ваш герой, даже если им была применена {Маскировка}. Также позволяет узнать характеристики близлежащего города, количество и вид находящихся в нем войск.\n";
// Меняем описание для Маскировки for(int i=1; i<4; i++) o_Spell[4].description[i] = \ "{""Маскировка""}\nДает ложную информацию вражескому герою, пытающемуся увидеть характеристики вашего героя.\n";
return EXEC_DEFAULT; }
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 (int 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); 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)); 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; // Уровень Школы магии воды для героя, который смотрит другого героя // (в том числе с применением Видения) int heroVision;
h->GetAddress() == ghostHeroHookAddr[0] ? heroReg = &c->esi : heroReg = &c->eax; h->GetAddress() == ghostHeroHookAddr[0] ? heroVision = *(int*)(c->ebp - 0x10) : heroVision = 0;
hero = *(_Hero_**)heroReg; disguise = (disguiseStruct*)&hero->disguise;
if ( hero->disguise != -1 ) //if ( disguise != -1 ) { // Копируем героя в "призрачного" героя *ghostHero = *hero; ghostHero->disguise = -1;
for (int i = 0; i < 7; ++i) { if ( hero->army.type[i] > ID_NONE ) { // Эксперт Магии воды может получить правдивую информацию // об армии противника if (heroVision < 3) 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 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; } 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/5/9 значений // для Базового/Продвинутого/Экспертного навыка Магии воздуха int count[4] = {3,3,5,9}; char Text[100]; sprintf(Text, "{%s}, select your army\nvisible 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 = 2;
// Расходуем ману CALL_2(int, __thiscall, 0x4D9540, hero, c->eax); // Проигрываем звук Disguise CALL_1(void, __thiscall, 0x59A770, o_Spell[4].wav_name); // Выполняем функцию, параметры для которой вернула функция воспроизведения WAV 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.NewDisguiseVision");
_PI->WriteCodePatch(0x41C7BA, "%n", 5); _PI->WriteCodePatch(0x4C7DA5, "%n", 3); _PI->WriteCodePatch(0x41C7C6, "%n", 6);
_PI->WriteLoHook(0x4C6CD9, decDisguise); _PI->WriteLoHook(0x41C7DD, setDisguise); // Для Новой игры _PI->WriteLoHook(0x4BFB30, setSpells); // Для Загрузить игру _PI->WriteLoHook(0x4BEFF0, setSpells);
for (int i = 0; i < 4; ++i) _PI->WriteLoHook(ghostHeroHookAddr[i], makeGhostHero); } }
return TRUE; }
Русская версия: Английская версия:
|