Объявления

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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

Сообщение AlexSpl » 11 окт 2017, 20:24

Изменения вполне в духе игры, а ещё решают проблемы с бесполезным навыком и заклинанием. Так почему бы и нет?
Вернуться к началу

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

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

Сообщение Ben80 » 11 окт 2017, 20:25

AlexSpl писал(а):

Мы действительно сделали много.


Для Вас, наверно, больше ничего интересного не будет. Рутина одна. Лично я вижу систему, в которой много небольших поправок, но для меня они очень важны. И все вместе они - система. Другие не смогут оценить. Если бы поиграли - тогда, возможно, оценили бы. Только играть пока не во что.
Вернуться к началу

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

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

Сообщение Ben80 » 11 окт 2017, 20:26

То есть для меня, например, возможность подправить навык Обучение или коэффициенты первичных параметров - значит не меньше, чем EagleEye или Disguise. А другим это неинтересно, в основном.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

Сообщение AlexSpl » 11 окт 2017, 20:26

Даёшь релиз Botvinnik Mod! :smile11:
Вернуться к началу

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

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

Сообщение Ben80 » 11 окт 2017, 20:27

А такое не слишком личное ?
https://www.google.ru/search?newwindow= ... 3ysQLifIf8
Вернуться к началу

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

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

Сообщение Ben80 » 11 окт 2017, 20:28

Не читал, но немного заинтересовался. Что программирование будущего - не инструкциями, а графикой, блок-схемами, например. Так оно голове легче гораздо. По идее.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5547
Зарегистрирован: 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)
Поблагодарили: 2162 раз.

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

Сообщение 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 раз.
Вернуться к началу

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

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

Сообщение Ben80 » 12 окт 2017, 13:42

AlexSpl, где-нибудь через неделю сможем вместе взяться за задачу понимания алгоритма, с помощью которого комп определяет, какой спелл ему применить в данный момент ? Хотя бы частичного понимания. То есть для начала хотя бы найти в коде "функцию полезности", которую он рассчитывает для каждого спелла и затем сравнивает эти значения.
Если помните, Вы писали код для Blind... :smile1:
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

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

Сообщение RoseKavalier » 12 окт 2017, 14:55

Привет)

I have edited my poorly placed post in plugin thread so it is now on-topic.

For reference, the contents were:
Цитата:
I think armorer fix can be more simple & complete (bug also exists with Air Shield) with this:
Код: Выделить всё
_PI->WriteByte(0x41E3A4, 0x4D);
_PI->WriteByte(0x41E4DF, 0x4D);
_PI->WriteByte(0x465944, 0x4D);

For HotA/WoG it will not change anything since it is already patched from what I recall.

For reference, 2011 post.
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

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

Сообщение RoseKavalier » 12 окт 2017, 20:08

I am too newbie to reply in private message system :P

Some more simple bugs/patches you can add:
Код: Выделить всё
// 65535 objects patch by AlexSpl
_PI->WriteByte(0x49C021, 0xB7);
_PI->WriteByte(0x4A763F, 0xB7);
_PI->WriteByte(0x4A9423, 0xB7);
_PI->WriteByte(0x4AA82E, 0xB7);
_PI->WriteByte(0x4C9662, 0xB7);
_PI->WriteHexPatch(0x4FD12A, "0F BF 78 24 83 FF FF 0F 84");
_PI->WriteByte(0x4FD164, 0xB7);
_PI->WriteHexPatch(0x00505C75, "0F BF 77 24 83 FE FF 74");
_PI->WriteByte(0x505C9F, 0xB7);
_PI->WriteHexPatch(0x52CD26, "0F BF 7F 24 83 FF FF 74");
_PI->WriteByte(0x52CD36, 0xB7);

// Repair Arena Cancel button (idea from igrik who removed 'Cancel' button)
_PI->WriteByte(0x49E4ED, 0x63);

// Show & Hide Forcefield Shadow
_PI->WriteJmp(0x5A365D, 0x5A3666);
_PI->WriteJmp(0x5A37B9, 0x5A37C2);
// around 0x5A36A5 check if spell == Forcefield and hook c->ebx = 0
// or
// _PI->WriteHexPatch(0x5A365D, "90 90 90 90 90 90 90 90 90");
// _PI->WriteHexPatch(0x5A37B9, "90 90 90 90 90 90 90 90 90");

// Wait Phase Bug
_PI->WriteJmp(0x464DF1, 0x464DFB);
// or
//_PI->WriteHexPatch(0x464DF1, "90 90 90 90 90 90 90 90 90 90");

// Rogue Sound
const char *rogue_sound = "rogu";
_PI->WriteDword(0x67448C, rogue_sound);

@ 0x42DDA6 (AI split shooters before combat), EBX can be 0 if fighting ghost hero -> crash to Desktop

NWCZION bug: *(_byte_*)0x6AAAC4 = 0
I used same spot as where baratorch fixes Keymaster Tents @0x4BEE60

Double check these as my plugin doesn't use patcher_x86 so I had to "translate".
Вернуться к началу

Пред.След.

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

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

Сейчас этот форум просматривают: Yandex [bot] и гости: 1