Объявления

Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

Как создать плагин для HD мода

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1318
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 08 окт 2017, 05:45

AlexSpl писал(а):

Пока работает только в сингле и хотсите. В сетевой игре длительность не уменьшается. Буду смотреть позже, в чём дело.


Вот здесь уменьшается, только приходиться устанавливать в 2 а не в 1.
_PI->WriteLoHook(0x4C700B, discountPackedDisguise);
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 08 окт 2017, 06:03

Сделал версию плагина newDisguise, которая работает в сетевой игре.

Код: Выделить всё
#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;

struct disguiseStruct
{
    char duration : 4;
    char index : 4;
    char unusedByte;
    short unusedWord;
} *disguise;

float getDisguiseMultiplier(int n)
{
    float multiplier[] = {0.0f, 1.5f, 2.0f, 3.0f, 5.0f};
    return n >= 0 ? multiplier[n] : 1.0f / multiplier[-n];
}

char* getArmyCountText(const _Hero_* hero, const int stackId, const int index = 0)
{
    char Text[10] = "";
   
    if ( hero->army.type[stackId] > ID_NONE )
    {
        int armyCount = (int)(getDisguiseMultiplier(index) * hero->army.count[stackId]);
       
        // Не палимся, если выбрали модификатор, отличный от нуля
        if ( index && armyCount < 1 ) armyCount = 1;
       
        armyCount < 10000 ? sprintf(Text, "%d", armyCount) : sprintf(Text, "%dk", armyCount / 1000);
    }
   
    return Text;
}

// Создаём стандартный задник с рамкой цвета игрока
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;
    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)
    {
        ((_DlgStaticText_*)dlg->GetItem(20 + i))->SetText(getArmyCountText(curHero, i, nPos));
    }

    // Устанавливаем ползунок в ближайшее к точке клика положение
    _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));
       
        // Добавляем надписи с численностью отрядов
        dlg->AddItem(_DlgStaticText_::Create(leftX + 1 + i * 34, 144, 32, 16,
            getArmyCountText(curHero, i), "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,
        "0%", "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;

    // 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 ( disguise->index && 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;
    bool disguiseCast = true;
    _Hero_* hero = (_Hero_*)c->esi;
   
    if ( hero->second_skill[HSS_AIR_MAGIC] )
    {
        curHero = hero;

        // Если у героя есть Магия Воздуха, показываем диалог с горизонтальной полосой прокрутки
        // на 3/5/9 значений для Базового/Продвинутого/Экспертного навыка
        char Text[100];
        sprintf(Text, "{%s}, select your army\nstrength modifier.", hero->name);
        yDlgShow(320, 256, (1 << hero->second_skill[HSS_AIR_MAGIC]) + 1, "{Disguise}", Text);
        disguiseCast = o_WndMgr->result_dlg_item_id == 30722;
    }

    // Индекс множителя маскировки помещаем в старший полубайт,
    // длительность "Маскировки" (2 хода) - в младший
    int spellCost = c->eax;
    if ( disguiseCast )
    {
        disguise = (disguiseStruct*)&hero->disguise;
        disguise->index = nPos;
        disguise->duration = 1;
    } else spellCost = 0; // Если заклинание отменено, устанавливаем расход маны в 0

    // Расходуем ману
    CALL_2(int, __thiscall, 0x4D9540, hero, spellCost);
   
    c->return_address = 0x41C7E5;
    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.TestDisguise");

            _PI->WriteCodePatch(0x4C7DA5, "%n", 3);
            _PI->WriteCodePatch(0x41C7C6, "%n", 6);
            _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;
}
Последний раз редактировалось AlexSpl 08 окт 2017, 09:48, всего редактировалось 1 раз.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1318
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 08 окт 2017, 06:12

"Выбрать модификатор силы армии" - это, скорее всего, тоже не очень подходит к духу игру.
В общем, на днях предложу финальный вариант плагина.

Большое спасибо за помощь, AlexSpl !
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 08 окт 2017, 06:13

Это же плагин для тестов. Меняйте описания.

Чтобы герою без Воздуха показывался диалог, достаточно удалить условие if ( hero->second_skill[HSS_AIR_MAGIC] )

Есть ещё такая тема в сетевой игре. Неактивные игроки не могут наблюдать за параметрами активного игрока в реальном времени. Например, если ходит красный и он делит армию, то синий, пока ждёт, будет видеть армию на начало хода. Так сетевая игра устроена. Поэтому, к примеру, если красный кастует Disguise, то остальные игроки увидят это, только когда до них дойдёт ход. Однако это компенсируется тем, что когда заклинание закончится, они этого не увидят, пока не настанет их ход. Хотелось бы поправить, но не пересылает игра изменения армии в реальном времени почему-то. Передвижения героя - да, а армию - нет.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1318
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 08 окт 2017, 09:09

Вот что у меня получилось после редактирования Вашего кода:

 Код
Код: Выделить всё
#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;

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];
}

char* getArmyCountText(const _Hero_* hero, const int stackId, const int index = 0)
{
    char Text[20] = "";

   if ( hero->army.type[stackId] > ID_NONE )
   {
      int armyCount = (int)(getDisguiseMultiplier(index) * hero->army.count[stackId]);
      armyCount < 10000 ? sprintf(Text, "%d", armyCount) : sprintf(Text, "%dт", armyCount / 1000);
   }
   
   return Text;
}      

// Создаём стандартный задник с рамкой цвета игрока
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;
    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)
    {
        ((_DlgStaticText_*)dlg->GetItem(20 + i))->SetText(getArmyCountText(curHero, i, nPos));
    }

    // Устанавливаем ползунок в ближайшее к точке клика положение
    _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));
       
        // Добавляем надписи с численностью отрядов
        dlg->AddItem(_DlgStaticText_::Create(leftX + 1 + i * 34, 144, 32, 16,
            getArmyCountText(curHero, i, 0), "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]);
            }
        }
     
        *(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;
    bool disguiseCast = true;
    _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);
    disguiseCast = o_WndMgr->result_dlg_item_id == 30722;

    // Индекс множителя маскировки помещаем в старший полубайт,
    // длительность "Маскировки" (2 хода) - в младший
    int spellCost = c->eax;
    if ( disguiseCast )
    {
        disguise = (disguiseStruct*)&hero->disguise;
        disguise->index = nPos;
        disguise->duration = 1;
    } else spellCost = 0; // Если заклинание отменено, устанавливаем расход маны в 0

    // Расходуем ману
    CALL_2(int, __thiscall, 0x4D9540, hero, spellCost);
   
    c->return_address = 0x41C7E5;
    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.TestDisguise");

            _PI->WriteCodePatch(0x4C7DA5, "%n", 3);
            _PI->WriteCodePatch(0x41C7C6, "%n", 6);
            _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;
}




Код: Выделить всё
char* getArmyCountText(const _Hero_* hero, const int stackId, const int index = 0)

Данная процедура работает немного волшебным образом - сначала после компиляции (изначально компилировал полностью Ваш код) вместо численности показывало крякозябры. Заменил
Код: Выделить всё
armyCount < 10000 ? sprintf(Text, "%d", armyCount) : sprintf(Text, "%dт", armyCount / 1000);
на
Код: Выделить всё
sprintf(Text, "%d", armyCount);
- все стало нормально. Также часто возникал такой вариант - увеличивал размер char Text[] - начинало нормально работать, за исключением первого показа (до скроллинга).
Работало полностью нормально только при удалении условия
Код: Выделить всё
armyCount < 10000

Сейчас условие оставил, увеличил только char Text[] - и все нормально, кроме того, что при первом запуске без скроллинга нет текста вообще (даже крякозябр).

Такое впечатление, что не только казалось бы несущественные правки кода меняют результат, но и при одном и том же коде иной раз результат компиляции различается.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 08 окт 2017, 09:46

Да, действительно. Так нельзя возвращать char*. Переделал.

Код: Выделить всё
#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;

struct disguiseStruct
{
    char duration : 4;
    char index : 4;
    char unusedByte;
    short unusedWord;
} *disguise;

float getDisguiseMultiplier(int n)
{
    float multiplier[] = {0.0f, 1.5f, 2.0f, 3.0f, 5.0f};
    return n >= 0 ? multiplier[n] : 1.0f / multiplier[-n];
}

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 ( index && 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;
    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);

    // 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,
        "0%", "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;

    // 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 ( disguise->index && 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;
    bool disguiseCast = true;
    _Hero_* hero = (_Hero_*)c->esi;
   
    if ( hero->second_skill[HSS_AIR_MAGIC] )
    {
        curHero = hero;

        // Если у героя есть Магия Воздуха, показываем диалог с горизонтальной полосой прокрутки
        // на 3/5/9 значений для Базового/Продвинутого/Экспертного навыка
        char Text[100];
        sprintf(Text, "{%s}, select your army\nstrength modifier.", hero->name);
        yDlgShow(320, 256, (1 << hero->second_skill[HSS_AIR_MAGIC]) + 1, "{Disguise}", Text);
        disguiseCast = o_WndMgr->result_dlg_item_id == 30722;
    }

    // Индекс множителя маскировки помещаем в старший полубайт,
    // длительность "Маскировки" (2 хода) - в младший
    int spellCost = c->eax;
    if ( disguiseCast )
    {
        disguise = (disguiseStruct*)&hero->disguise;
        disguise->index = nPos;
        disguise->duration = 1;
    } else spellCost = 0; // Если заклинание отменено, устанавливаем расход маны в 0

    // Расходуем ману
    CALL_2(int, __thiscall, 0x4D9540, hero, spellCost);
   
    c->return_address = 0x41C7E5;
    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.TestDisguise");

            _PI->WriteCodePatch(0x4C7DA5, "%n", 3);
            _PI->WriteCodePatch(0x41C7C6, "%n", 6);
            _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;
}

newDisguise.zip
(7.39 КБ) Скачиваний: 239
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1318
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 08 окт 2017, 10:10

А каким образом в Ваш код лучше всего внести изменение в правильное проигрывание звукового файла ?
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1318
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 08 окт 2017, 10:11

У меня вот такое работает:

Код: Выделить всё
int __stdcall setDisguise(LoHook* h, HookContext* c)
{
    nPos = 0;
    bool disguiseCast = true;
    _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);
   sprintf(Text, "{%s}, select falsified\narmy strength", hero->name);
    yDlgShow(320, 256, count[hero->second_skill[HSS_AIR_MAGIC]], "{Disguise}", Text);
    disguiseCast = o_WndMgr->result_dlg_item_id == 30722;

    // Индекс множителя маскировки помещаем в старший полубайт,
    // длительность "Маскировки" (2 хода) - в младший
    int spellCost = c->eax;
   
    if ( disguiseCast )
    {
        disguise = (disguiseStruct*)&hero->disguise;
        disguise->index = nPos;
        disguise->duration = 1;
    } else// spellCost = 0; // Если заклинание отменено, устанавливаем расход маны в 0
   {
      c->return_address = 0x41C7E5;
      return NO_EXEC_DEFAULT;
   }

    // Расходуем ману
    CALL_2(int, __thiscall, 0x4D9540, hero, spellCost);

   c->eax = 0x6854A0;
   c->ecx = *(int*)(0x6856C4);
   CALL_0(__int64, __fastcall, 0x59A770);
   c->ecx = c->esi;
   
    c->return_address = 0x41C7E5;
    return NO_EXEC_DEFAULT;
}
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 08 окт 2017, 11:02

Звуки на месте + диалог, когда нет Воздуха:

 WAV
Код: Выделить всё
#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;

struct disguiseStruct
{
    char duration : 4;
    char index : 4;
    char unusedByte;
    short unusedWord;
} *disguise;

float getDisguiseMultiplier(int n)
{
    float multiplier[] = {0.0f, 1.5f, 2.0f, 3.0f, 5.0f};
    return n >= 0 ? multiplier[n] : 1.0f / multiplier[-n];
}

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 ( index && 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;
    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);

    // 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,
        "0%", "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;

    // 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 ( disguise->index && 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 значений для Базового/Продвинутого/Экспертного навыка
    char Text[100];
    sprintf(Text, "{%s}, select your army\nstrength modifier.", hero->name);
    yDlgShow(320, 256, (1 << hero->second_skill[HSS_AIR_MAGIC]) + 1, "{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));
    }
   
    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.TestDisguise");

            _PI->WriteCodePatch(0x4C7DA5, "%n", 3);
            _PI->WriteCodePatch(0x41C7C6, "%n", 6);
            _PI->WriteCodePatch(0x41C7BA, "%n", 5);
            _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;
}
Последний раз редактировалось AlexSpl 08 окт 2017, 11:12, всего редактировалось 1 раз.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: Как создать плагин для HD мода

Сообщение AlexSpl » 08 окт 2017, 11:10

Убрал вызов функции sub_59A7C0. Всё-таки ей нужно передавать аргументы. Без неё работает, но пока только для тестов вариант со звуком выше :smile5:
Последний раз редактировалось AlexSpl 08 окт 2017, 11:15, всего редактировалось 1 раз.
Вернуться к началу

Пред.След.

Вернуться в Общий раздел

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1