Объявления

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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
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 » 03 май 2021, 19:37

Ben80, а Вы знаете, как разрешить строить? Потому что разрешить нанимать очень просто: нужно в конец вектора добавить существо из портала, и AI будет рассматривать его найм (и точно нанимать, когда у него отстроены только жилища нижних уровней). Возможно, правильно нужно будет указать sourceArmyCounts в

Код: Выделить всё
struct AIStackToRecruit
{
    int creatureType;
    short* sourceArmyCounts;
    short creaturesAvailable;
    char r1;
    char r2;
    void updateAvailableCreatures();
} *AIStacksToRecruit = new AIStackToRecruit[16];
Вернуться к началу

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

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

Сообщение Ben80 » 03 май 2021, 19:47

AlexSpl писал(а):

Ben80, а Вы знаете, как разрешить строить?


У меня просто нет сейчас на компе декомпилированного кода, нет IDA и VisualStudio :smile1:

Поэтому попробую описать :smile1: Добавлять код нужно в ту же самую процедуру, где ИИ взвешивает постройку двеллингов и некоторых других строений. Например, Necromancy Amplifier. Сейчас попробую посмотреть в соседний теме адрес.

***

Вот, нашел.
Код: Выделить всё
...
_PI->WriteLoHook(0x42B131, correctAmplifierAIValue);


Значит это нужно делать в той процедуре, внутри которой адрес 0x42B131.
Вы же можете посмотреть декомпилят этой процедуры - после просмотра должно быть более-менее понятно.

Правда, придется подумать, как рассчитать вес. Но это уже приятная творческая часть. :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 » 03 май 2021, 20:01

Я обычно с дебаггером прохожусь по новому коду, чтобы быстрее понять, как всё работает. Зачастую быстрее понимаешь, что делает функция, чем когда анализируешь декомпилированный листинг. Плюс при пошаговом исполнении инструкций можно поиграть с содержимым регистров (в том числе EIP! и регистром флагов).
Вернуться к началу

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

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

Сообщение Ben80 » 03 май 2021, 20:19

Да, я и забыл, что вы ассемблер предпочитаете.

Процедура (0x42AE00), конечно, очень сложная (я ее до конца так и не понял). Гораздо проще было бы добавить постройку Портала Призыва в той же процедуре, где строится Академия боевых искусств. Но это была бы халтура - Академия строится для нужд героя-гостя (и другие постройки в этой процедуре - тоже для героя-гостя).
Вернуться к началу

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 » 03 май 2021, 20:26

Цитата:
Да, я и забыл, что вы ассемблер предпочитаете.

Листинг не покажет Вам содержимое регистров и памяти в каждый конкретный момент. Нормально им пользоваться можно потому, что есть heroes3f.idb, дебаг мап Эры и т.д. Вы попробуйте разобрать листинг на чистой базе IDA :smile1: Плюс моего подхода заключается в том, что можно быстро понять, что именно в каком регистре. Навёл мышку, а тебе всплывающее окошко со структурой, на которую он указывает. Хочешь - результат cmp поменял и пошёл не по той ветке, по которой бы пошла игра. Хочешь - откатился и повторил. Короче, много преимуществ перед листингом. А ещё декомпилятор будет генерить неуместные stdcall, cdecl, long double, когда там fastcall, thiscall, float, например. И очень часто аргументы неверно интерпретирует. Но для простых функций, в которых используются известные структуры, конечно, незаменим. Но когда встречается новая, одним листингом не обойтись.
Вернуться к началу

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

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

Сообщение RoseKavalier » 03 май 2021, 22:22

Side-by-side disassembler and debugger is the best!
Static analysis works well once you have enough information worked in and can deduce more things.

Interesting discussion, though I do not have much to contribute at this time due to time constraints, I will follow closely and can always perform quick static analysis :smile14:
Вернуться к началу

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

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

Сообщение Ben80 » 04 май 2021, 06:45

В процедуре 0x42AE00 для возможных построек рассчитывается "профит" и расходы. Для Портала Вызова, думаю, было бы честно определить профит как "средневзвешенный" от профита по имеющимся у игрока внешним двеллингам (профит от внешних двеллингов и базовый (без цитадели) от внутренних одинаковый, а как находить профит для внутренних двеллингов - ясно из процедуры).
Расходы же на постройку Портала очевидны.
Вернуться к началу

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 » 05 май 2021, 13:27

Новые внешние двеллинги (первый уровень платно; при наличии ул. постройки - возможность выбора между грейженым и негрейженым существом):

Код: Выделить всё
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include "..\..\HotA\homm3.h"

Patcher* _P;
PatcherInstance* _PI;

int getCreatureBasicType(const int id)
{
    int basicType = id;
   
    if ( id % 2 && (id < CID_AIR_ELEMENTAL || id == CID_SPRITE || id == CID_MAGIC_ELEMENTAL || id == CID_PHOENIX) )
        basicType = id - 1;
    else
    switch ( id )
    {
    case CID_STORM_ELEMENTAL:
        basicType = CID_AIR_ELEMENTAL;
        break;
    case CID_MAGMA_ELEMENTAL:
        basicType = CID_EARTH_ELEMENTAL;
        break;
    case CID_ENERGY_ELEMENTAL:
        basicType = CID_FIRE_ELEMENTAL;
        break;
    case CID_ICE_ELEMENTAL:
        basicType = CID_WATER_ELEMENTAL;
        break;
    }

    return basicType;
}

int getCreatureUpgradeType(const int id)
{
    return CALL_1(int, __fastcall, 0x47AAD0, id);
}

_Dwelling_* GetDwelling(const int id)
{
    return (_Dwelling_ *)(o_GameMgr->Field<int>(0x4E39C) + 92 * id);
}

_Dwelling_* getDwelling(const _Hero_* hero)
{
    _Dwelling_* dwelling = 0;
   
    if ( hero )
    {
        _MapItem_* item = o_GameMgr->Map.GetItem(hero->x, hero->y, hero->z);
        if ( item && (item->object_type == 0x11 || item->object_type == 0x14) ) dwelling = GetDwelling(item->setup);
    }

    return dwelling;
}

bool playerHasUpgDwelling(const int id)
{
    bool hasUpgDwelling = false;

    for (int i = 0; i < o_ActivePlayer->towns_count; ++i)
    {
        _Town_* town = o_GameMgr->GetTown(o_ActivePlayer->towns_ids[i]);
        if ( town && o_pCreatureInfo[id].town == town->type &&
            town->IsBuildingBuilt(37 + o_pCreatureInfo[id].level, 1) )
        {
            hasUpgDwelling = true;
            break;
        }
    }

    return hasUpgDwelling;
}

void __stdcall setupDwelling(HiHook* h, _AdvMgr_* advMgr, _Hero_* hero, _MapItem_* item, int a4, int a5)
{
    _Dwelling_* dwelling = GetDwelling(item->setup);
           
    if ( dwelling->type == 0x11 )
    {
        int upgCreatureId = getCreatureUpgradeType(dwelling->creature_types[0]);
       
        if ( upgCreatureId != ID_NONE && playerHasUpgDwelling(upgCreatureId) )
        {
            if ( o_ActivePlayer->IsHuman() )
            {
                dwelling->creature_types[1] = dwelling->creature_types[0];
                dwelling->creature_counts[1] = dwelling->creature_counts[0];
            }

            dwelling->creature_types[0] = upgCreatureId;
           
            if ( dwelling->defenders.count[0] > 0 )
                dwelling->defenders.type[0] = upgCreatureId;
        }
    }

    CALL_5(void, __thiscall, h->GetDefaultFunc(), advMgr, hero, item, a4, a5);

    if ( dwelling->type == 0x11 )
    {   
        dwelling->creature_types[0] = getCreatureBasicType(dwelling->creature_types[0]);
        if ( dwelling->creature_types[1] != ID_NONE)
            dwelling->creature_counts[0] = min(dwelling->creature_counts[0], dwelling->creature_counts[1]);
        dwelling->creature_types[1] = ID_NONE;
        dwelling->creature_counts[1] = 0;
        if ( dwelling->defenders.count[0] > 0 )
            dwelling->defenders.type[0] = dwelling->creature_types[0];
    }
}

int __stdcall afterHiring(LoHook* h, HookContext* c)
{
    _Dwelling_* dwelling = 0;
   
    if ( o_ActivePlayer->selected_hero_id != ID_NONE )
        dwelling = getDwelling(&o_GameMgr->hero[o_ActivePlayer->selected_hero_id]);
   
    if ( dwelling && dwelling->type == 0x11 )
    {
        c->return_address = 0x55121B;
        return NO_EXEC_DEFAULT;
    }

    return EXEC_DEFAULT;
}

int __stdcall skipMessages(LoHook* h, HookContext* c)
{
    if ( _P->VarGetValue("HD.UI.AdvMgr.SkipMapMsgs", 1) )
    {
        c->return_address = 0x4A1917;
        return NO_EXEC_DEFAULT;
    }

    return EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    static bool plugin_On = false;

    if ( DLL_PROCESS_ATTACH == ul_reason_for_call )
    {
        if ( !plugin_On )
        {
            plugin_On = true;
            _P = GetPatcher();
            _PI = _P->CreateInstance((char*)"HD.Plugin.UpgradedDwellings");

            // Пропускаем сообщения при HD.UI.AdvMgr.SkipMapMsgs = 1
            _PI->WriteLoHook(0x4A17BD, skipMessages);
            // Устанавливаем тип существ и защитников при посещении двеллинга
            _PI->WriteHiHook(0x4A1520, SPLICE_, EXTENDED_, THISCALL_, setupDwelling);
            // Закрываем диалог после нажатия на кнопку покупки
            _PI->WriteLoHook(0x5510B1, afterHiring);
                       
            // Убираем бесплатное присоединение существ из двеллингов 1-го уровня
            _PI->WriteHexPatch(0x4A197B, "90 90");
            _PI->WriteHexPatch(0x4AB812, "90 90");
           
            // AI
            // Убираем бесплатное присоединение существ из двеллингов 1-го уровня
            _PI->WriteHexPatch(0x42CC06, "90 90 90");
        }
    }

    return TRUE;
}

UPD: Добавил пропущенную проверку на 0x11 двеллинг.
Последний раз редактировалось AlexSpl 05 май 2021, 15:31, всего редактировалось 4 раз(а).
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

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

Сообщение Rolex » 05 май 2021, 15:26

AlexSpl, я так понял улучшенные алгоритмы по скупки существ AI в городе Вы сюда не включали? Если так, то все верно. То есть в этом плагине должен быть только улучшенный алгоритм AI по скупке существ во внешних жилищах при появлении грейженных существ. Плагин по улучшению AI, который не касается грейда в жилищах, лучше вынести отдельно. Пока он будет по скупке существ в городе, а потом может еще что-то в него добавится. Его лучше развивать отдельно.

При этом, AlexSpl, опубликуйте, пожалуйста, еще два кода:
1) Тот же плагин, что и этот в плане скупки существ AI в жилищах, со всеми фиксаими, но грейд на постоянной основе, как было изначалаьно. Или просто скажите, что убрать/добавить/закомментить в этом коде, чтобы получить, грейд на постоянной основе. Чтоб было у меня и то и другое.
2) Плагин с улучшенные алгоритмами по скупке существ AI в городе (последняя Ваша версия), то что Вы уже успели сделать вместе дебаг-модом (можно его закомментить).
Последний раз редактировалось Rolex 05 май 2021, 15:52, всего редактировалось 2 раз(а).
Вернуться к началу

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 » 05 май 2021, 15:40

Цитата:
1) Тот же плагин, что и этот в плане скупки существ AI в жилищах, со всеми фиксаими, но грейд на постоянной основе, как было изначалаьно. Или просто скажите, что убрать/добавить/закомментить в этом коде, чтобы получить, грейд на постоянной основе. Чтоб было у меня и то и другое.

Уберите проверку playerHasUpgDwelling() в хайхуке.

Цитата:
2) Плагин с улучшенные алгоритмами по скупке существ AI городе (последняя Ваша версия), то что Вы уже успели сделать вместе дебаг-модом (можно его зокомментить).

Как только будет готов.
Вернуться к началу

Пред.След.

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

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

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

cron