Объявления

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

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

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

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

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

А сделать просто, так как это было раньше, не реально ?
То есть хук в функции 4C6CA0, может быть даже в 4C700B.

Ведь работало же именно таким правильным образом, в хот-сите, когда хук был в конце функции 4C6CA0.
Ну и, может быть, нужно было просто поставить его не в конец а куда-нибудь в 4C700B
Вернуться к началу

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, 18:04

Формула неправильная, блин (счас исправлю) :smile14: но идея понятна: уменьшать Disguise героев игрока ровно через N - 1 ходов игроков.
Вернуться к началу

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

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

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

Ben80 писал(а):

Жесть :smile1:

Однако, страшновато. Где тонко - там рвется.


Впрочем, всякое бывает. Бывает, что сложное работает надежно, а что-то простое, что вроде бы должно железно работать - не работает.
Вернуться к началу

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, 19:11

Элементарная математика спасёт мир. Убираем newDay и переписываем decDisguise:

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


Works like a charm (в хотсите, правда). Тестил для трёх игроков.
Вернуться к началу

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, 19:12

Можете потестить для двух? А я проверю для 4-х.
Вернуться к началу

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

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

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

Что может неправильно работать в хуке на 5C1892 ?
Не хуки ли HD мода виновны ?

Код: Выделить всё
int __stdcall disguiseTownGuards(LoHook* h, HookContext* c)
{
    _Hero_* hero;
   hero = o_GameMgr->GetHero(c->edx);
   c->eax = (int)(&hero->army);

    return EXEC_DEFAULT;
}


Код: Выделить всё
Exception
{
   Module:    Heroes3 HD.exe
   Adress:      0x0047B860
   Code:        EXCEPTION_ACCESS_VIOLATION
   Flags:       0x00000000
   Information: read of address: 0xFEDE9078
}
Вернуться к началу

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

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

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

AlexSpl писал(а):

Можете потестить для двух? А я проверю для 4-х.


По сети ? Могу.
Вернуться к началу

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, 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 при игре с компами. Тем не менее :smile1:
Вернуться к началу

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

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

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

Ваш код попробовал. Работает.

Я в принципе уже догадался что мой хук нужно ставить внутри
//----- (00530600) --------------------------------------------------------
_Dlg_ *__thiscall Dlg_TownSmallRMCInfo(_Dlg_ *ecx0, int Town, signed int a3)
Вернуться к началу

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, 19:25

Сейчас не могу о другом думать. Попробую сетевую игру потестить.

Есть ещё случай, когда кто-то из игроков погибает. Надо его тоже учитывать.

Так. Пишу сетевую игру. Есть отличия.
Вернуться к началу

Пред.След.

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

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

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