Объявления

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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 890
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 49 раз.

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

Сообщение Rolex » 10 янв 2021, 10:47

aronir писал(а):

Это я так понимаю, не заданы какие то переменные.
Возможно уже есть готовый плагин, то прошу дать ссыль.
Надоело уже по жилищам каждую неделю бегать, в ХОТе с этим проще(

В данном случае используется структура _Dwelling_ из библиотеки homm3.h. Вам необходимо подключить эту библиотеку в вашем проекте. Для этого скачайте по ссылке архив
http://handbookhmm.ru/forum/download/file.php?id=1550
и поместите его содержимое (папка HotA) в папку с проектом, а именно туда, где находится dllmain.cpp. После чего в исходном коде подключите эту библиотеку, а также добавьте строчку
#define _CRT_SECURE_NO_WARNINGS перед подключением библиотек.

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


patcher_x86.hpp будет подключен непосредственно из самой homm3.h. Для VS 2015 (и, возможно, более новых), нужно еще структуру _Dwelling_ из homm3.h, там где NOALIGN struct _Dwelling_, обернуть в #pragma pack(push, 1) ... #pragma pack(pop). При построении dll обязательно ставьте выравнивание структур в 1 байт и конфигурацию решения в Release.
Последний раз редактировалось Rolex 16 янв 2021, 14:34, всего редактировалось 2 раз(а).
Вернуться к началу

offlinearonir  
имя: aronir
 
Сообщения: 3
Зарегистрирован: 07 янв 2021, 19:21
Пол: Мужчина
Поблагодарили: 0 раз.

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

Сообщение aronir » 11 янв 2021, 06:55

Rolex спасибо скомпилировалось и заработало, но не все строки прописывал, но вроде работает адекватно.
Прикрепил dll'ку.
Вложения
nakoplenie.zip
Плагин для накопления существ, если жилище принадлежит игроку.
(3.43 КБ) Скачиваний: 124
Вернуться к началу

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

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

Сообщение Rolex » 16 янв 2021, 14:27

AlexSpl, имеется ваш код для отображения кол-ва охранников в банке. Вы позже добавили туда еще и Утопию, но без Склепа. А не подскажите, как сюда добавить еще и Склеп?

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

using namespace std;

Patcher* _P;
PatcherInstance* _PI;
static _bool_ plugin_On = 0;

string getInterval(int n) {
    string str = "1-4";
    if ( n > 999 ) str = "1000+"; else
    if ( n > 499 ) str = "500-999"; else
    if ( n > 249 ) str = "250-499"; else
    if ( n > 99 ) str = "100-249"; else
    if ( n > 49 ) str = "50-99"; else
    if ( n > 19 ) str = "20-49"; else
    if ( n > 9 ) str = "10-19"; else
    if ( n > 4 ) str = "5-9";
    return str;
}

int __stdcall showGuards(LoHook* h, HookContext* c)
{
    bool isUtopia = h->GetAddress() == 0x4A1E56;

    // Получаем состояние банка
    _CrBankState_* bankState = (_CrBankState_*)CALL_1(int, __fastcall, 0x405D80, isUtopia ? c->edi : c->ebx);

    int CreaturesCount = bankState->defenders.GetCreaturesCount();
   
    string str = (char*)c->ecx; // Оригинальное сообщение
    str = str + "\n\nAmount: " + getInterval(CreaturesCount);
       
    // Утопия?
    if ( isUtopia ) {
        str = str + " (" + getInterval(bankState->defenders.count[0]) + ", " + getInterval(bankState->defenders.count[1]) + ", " +
            getInterval(bankState->defenders.count[2]) + ", " + getInterval(bankState->defenders.count[3]) + ")";
    } else
    // Если есть грейд
    if ( bankState->defenders.type[2] != bankState->defenders.type[0]) {
        str = str + " (" + getInterval(CreaturesCount - bankState->defenders.count[2]) + ", " + getInterval(bankState->defenders.count[2]) + ")";
    }
           
    // Передаём адрес текстового буфера в качестве аргумента для диалога
    sprintf(o_TextBuffer, "%s", str);
    c->ecx = (int)o_TextBuffer;
   
    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.ShowGuards");

            _PI->WriteLoHook(0x4A13E6, showGuards);
            _PI->WriteLoHook(0x4A1E56, showGuards);
        }
    }

    return TRUE;
}
Вернуться к началу

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 » 19 янв 2021, 12:23

Немного доработанный код, показывающий также тип отрядов:

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

using namespace std;

Patcher* _P;
PatcherInstance* _PI;
static _bool_ plugin_On = 0;

#define o_CreatureInfo ((_CreatureInfo_*)0x6703B8)

string getInterval(int n) {
    string str = "1-4";
    if ( n > 999 ) str = "1000+"; else
    if ( n > 499 ) str = "500-999"; else
    if ( n > 249 ) str = "250-499"; else
    if ( n > 99 ) str = "100-249"; else
    if ( n > 49 ) str = "50-99"; else
    if ( n > 19 ) str = "20-49"; else
    if ( n > 9 ) str = "10-19"; else
    if ( n > 4 ) str = "5-9";
    return str;
}

int __stdcall showGuards(LoHook* h, HookContext* c)
{
    // Получаем состояние банка
    _CrBankState_* bankState = (_CrBankState_*)CALL_1(int, __fastcall, 0x405D80, *(int*)(c->ebp + 0xC));
   
    string str = (char*)c->ecx; // Оригинальное сообщение
    str += "\n";
       
    for (int i = 0; i < bankState->defenders.GetStacksCount(); ++i)
        str = str + "\n" + o_CreatureInfo[bankState->defenders.type[i]].name_plural + ": " +
        getInterval(bankState->defenders.count[i]);
           
    // Передаём адрес текстового буфера в качестве аргумента для диалога
    sprintf(o_TextBuffer, "%s", str.c_str());
    c->ecx = (int)o_TextBuffer;
   
    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((char*)"HD.Plugin.ShowGuards");

            _PI->WriteLoHook(0x4A13E6, showGuards);
            _PI->WriteLoHook(0x4A1E56, showGuards);
            _PI->WriteLoHook(0x4AC1B9, showGuards);
        }
    }

    return TRUE;
}
Вернуться к началу

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

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

Сообщение Rolex » 19 янв 2021, 14:34

Спасибо. Интересное решение с типом отрядов. Но со Склепом получается, что охрана отображается только при входе в банк с охранной. А вот если отказатся, отойти и проверить охрану по правой клавише мыши, то увидим (Не посещено). Хотя с другими банками проблем нет, там все ок, после посещения и отказа (Под охраной: Толпа (20-49) Гномы ... например, Сокровищница гномов).

Также думаю, неплохо было бы добавить сюда доступных для найма существ во внешних жилищах и Лагере беженцев. Тут должна быть похожая реализация. Чтобы после посещения героем игрока внешнего жилища по ПКМ по нему дописывалось во всплывающем окне: имя существ, которые обитают в данном жилище и их точное количество, которое доступно для найма на данный момент (полезно юзать вместе с плагином для накопления). Например,

Доступно для найма:
Гномы - 24
Вернуться к началу

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 » 19 янв 2021, 15:55

Цитата:
А вот если отказатся, отойти и проверить охрану по правой клавише мыши, то увидим (Не посещено). Хотя с другими банками проблем нет, там все ок

Это стандартный алгоритм игры. Сделано это для того, чтобы игрок мог, ничего не подозревая, получить -1 к Боевому духу :smile1: Хорошо, неосторожный игрок :smile1:

Чтобы количество защитников после посещения банка и отказа от боя показывалось в диалоге по правому клику, нужно прописать ещё три дополнительных хука (для стандартных банков, Утопии и Склепа). А есть ещё Кораблекрушение и Покинутый корабль. Всего десять получится.

Получить эти места можно, например, поставив брейкпоинт на sub_4FC600 (кажется, так). На sub_4F6C00, то есть. Или условный hardware-брейкпоинт на сам текстовый буфер.
Вернуться к началу

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

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

Сообщение Rolex » 19 янв 2021, 18:04

AlexSpl писал(а):

Получить эти места можно, например, поставив брейкпоинт на sub_4FC600 (кажется, так). На sub_4F6C00, то есть. Или условный hardware-брейкпоинт на сам текстовый буфер.

Что для этого нужно и как это сделать? Я подобные вещи лучше всего понимаю на конкретных, подробных, пошаговых примерах. То есть, если для Склепа мне пошагово все показать на примере, то может для кораблей я и сам сделаю. Но понимаю, что все эти разьяснения могут занят больше времени, чем найти эти три хука самостоятельно. Ну смотрите как вам будет удобно. За любую помощь в любом случае буду благодарен.
Вернуться к началу

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 » 19 янв 2021, 18:22

Да, действительно, на создание туториала уйдёт намного больше времени, чем просто на поиск адресов для хуков. Но найти адрес - это не всё, ещё придётся проанализировать код, найти, где что в памяти или каких регистрах лежит, и т.п. Я какие-то базовые вещи по поиску адресов с помощью брейкпоинтов рассказывал. Возможно, не в этой теме. Но помню, что пошаговыми инструкциями делился в теме про моддинг в Героях 2. Правда, человеку, совсем не знакомому с языком ассемблера, они помогут разве что в аналогичных случаях, так что их ценность весьма сомнительна :smile2:

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

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

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

Сообщение Rolex » 19 янв 2021, 18:26

Цитата:
Попробую позже кратко рассказать, как получить место для хука, который бы показывал охрану склепа в диалоге по правому клику.

Спасибо, буду ждать. Только что проверил для стандартных банков и Утопии, там все отображается. То есть не отображается только для Склепа, Кораблекрушения и Покинутого корабля.
Вернуться к началу

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 » 19 янв 2021, 19:33

Всё-таки расписывать по шагам - много текста :smile14:

Вот черновой код, который показывает охранников по правому клику (посещение пока не проверяется):

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

using namespace std;

Patcher* _P;
PatcherInstance* _PI;
static _bool_ plugin_On = 0;

#define o_CreatureInfo ((_CreatureInfo_*)0x6703B8)

string getInterval(int n) {
    string str = "1-4";
    if ( n > 999 ) str = "1000+"; else
    if ( n > 499 ) str = "500-999"; else
    if ( n > 249 ) str = "250-499"; else
    if ( n > 99 ) str = "100-249"; else
    if ( n > 49 ) str = "50-99"; else
    if ( n > 19 ) str = "20-49"; else
    if ( n > 9 ) str = "10-19"; else
    if ( n > 4 ) str = "5-9";
    return str;
}

int __stdcall showGuards(LoHook* h, HookContext* c)
{
    // Получаем состояние банка
    _CrBankState_* bankState = (_CrBankState_*)CALL_1(int, __fastcall, 0x405D80, *(int*)(c->ebp + 0xC));
   
    string str = (char*)c->ecx; // Оригинальное сообщение
    str += "\n";
       
    for (int i = 0; i < bankState->defenders.GetStacksCount(); ++i)
        str = str + "\n" + o_CreatureInfo[bankState->defenders.type[i]].name_plural + ": " +
        getInterval(bankState->defenders.count[i]);
           
    // Передаём адрес текстового буфера в качестве аргумента для диалога
    sprintf(o_TextBuffer, "%s", str.c_str());
    c->ecx = (int)o_TextBuffer;
   
    return EXEC_DEFAULT;
}

int objID;

int __stdcall saveObjID(LoHook* h, HookContext* c)
{
    objID = *(int*)(c->eax + 0x1E);
   
    return EXEC_DEFAULT;
}

int __stdcall showGuardsRMB(LoHook* h, HookContext* c)
{
    // Проверяем ID объекта (может, можно сразу проверить, банк ли это, но нужно время на анализ кода)
    // objID = 0x10 - стандартные банки, objID = 0x54 - Склеп (можно поискать остальные ID, наверняка есть в том же ERM help)
    if ( objID == 0x10 || objID == 0x54 )
    {
        // Получаем состояние банка
        _CrBankState_* bankState = (_CrBankState_*)CALL_1(int, __fastcall, 0x405D80, c->edi);
       
        string str = (char*)c->ecx; // Оригинальное сообщение
        str += "\n";
           
        for (int i = 0; i < bankState->defenders.GetStacksCount(); ++i)
            str = str + "\n" + o_CreatureInfo[bankState->defenders.type[i]].name_plural + ": " +
            getInterval(bankState->defenders.count[i]);
               
        // Передаём адрес текстового буфера в качестве аргумента для диалога
        sprintf(o_TextBuffer, "%s", str.c_str());
        c->ecx = (int)o_TextBuffer;
    }
   
    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((char*)"HD.Plugin.ShowGuards");

            _PI->WriteLoHook(0x4A13E6, showGuards);
            _PI->WriteLoHook(0x4A1E56, showGuards);
            _PI->WriteLoHook(0x4AC1B9, showGuards);
           
            // Можно без этого хука, но иначе нужно вычислять, а это всегда занимает больше времени :)
            _PI->WriteLoHook(0x413917, saveObjID);
           
            // RMB
            _PI->WriteLoHook(0x415AEE, showGuardsRMB);
        }
    }

    return TRUE;
}


Цитата:
То есть не отображается только для Склепа, Кораблекрушения и Покинутого корабля.

Это из-за сюрприза в виде -1 Морали. Т.е. мы зачистили объект, пришёл второй игрок, чекнул, отошёл. Должен ли он видеть, что объект пуст (что сразу исключает его посещение из-за сюрприза)? :smile1:

* * *
Да, есть вылет, когда курсор над объектом не вздыбленный конь. Пофикшу завтра уже. Всё таки вход вычислять придётся :smile1:

 
Вот тут ошибка:

Код: Выделить всё
// Получаем состояние банка
_CrBankState_* bankState = (_CrBankState_*)CALL_1(int, __fastcall, 0x405D80, c->edi);

Вместо c->edi нужен адрес входа в объект.
Вернуться к началу

Пред.След.

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

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

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