Объявления
Поздравляем
Roman2211


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

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

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

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

Сообщение Rolex » 20 янв 2021, 08:32

AlexSpl писал(а):

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

Да, действительно, Вы правы, все логично.

AlexSpl писал(а):

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

Ок. :smile2:
Вернуться к началу

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 » 20 янв 2021, 11:08

Исправленный код. У объектов Crypt, Derelict Ship и Shipwreck не устанавливается флаг посещения (именно посещения без зачистки), поэтому можно либо просто не проверять, посещён ли банк, отображая о нём информацию всегда (но такой вариант разве что для разведки карты годится), либо завести глобальный массив (можно список) посещённых банков в коде самого плагина. Банк однозначно идентифицируется по адресу его тайла-входа (mapItem), а отмечать посещение можно в хуке showGuards. Но это уже элементарная задача, не относящаяся к реверсу.

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

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

#define o_CreatureInfo ((_CreatureInfo_*)0x6703B8)

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

_MapItem_* mapItem;

int __stdcall saveObjEntranceAddr(LoHook* h, HookContext* c)
{
    mapItem = (_MapItem_*)c->eax;
   
    return EXEC_DEFAULT;
}

int __stdcall showGuardsRMB(LoHook* h, HookContext* c)
{
    if ( mapItem && mapItem->IsVisited(o_ActivePlayerID) )
    {
        // mapItem->object_type = 0x10 - стандартные банки, 0x18 - Derelict Ship, 0x19 - Dragon Utopia, 0x54 - Crypt, 0x55 - Shipwreck
        int objID = mapItem->object_type;
        if ( mapItem->object_type == 0x10 || mapItem->object_type == 0x18 || mapItem->object_type == 0x19 ||
             mapItem->object_type == 0x54 || mapItem->object_type == 0x55 )
        {
            // Получаем состояние банка
            _CrBankState_* bankState = (_CrBankState_*)CALL_1(int, __fastcall, 0x405D80, mapItem);
           
            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); // Dragon Utopia
            _PI->WriteLoHook(0x4AC1B9, showGuards); // Crypt, Derelict Ship, Shipwreck
           
            // Сохраняем адрес тайла-входа в объект
            _PI->WriteLoHook(0x413917, saveObjEntranceAddr);
           
            // Сообщения по правому клику
            _PI->WriteLoHook(0x415AEE, showGuardsRMB);
        }
    }

    return TRUE;
}

* * *

А ещё, если очень хочется, можно самому устанавливать флаг посещения банков (замените текст хука showGuards на следующий):
Код: Выделить всё
int __stdcall showGuards(LoHook* h, HookContext* c)
{
    // Получаем состояние банка
    _MapItem_* mapItem = (_MapItem_*)*(int*)(c->ebp + 0xC);
    _CrBankState_* bankState = (_CrBankState_*)CALL_1(int, __fastcall, 0x405D80, mapItem);
   
    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;

    mapItem->SetAsVisited(o_ActivePlayerID);
   
    return EXEC_DEFAULT;
}

:!: Заменил o_MeID на o_ActivePlayerID.

Нужно как-нибудь разобраться. Когда писали с Ben80 плагины для Eagle Eye и Disguise, вроде, разобрался. А теперь вот снова всё забыл :smile14:
o_MeID - это идентификатор игрока, но почему-то в хот-сите он является идентификатором первого игрока даже во время хода другого.
o_ActivePlayerID - это идентификатор активного игрока, т.е. того, который ходит. Но что происходит в сетевой игре? Сможет ли игрок корректно видеть информацию о банках в сетевой игре не во время его хода?
Последний раз редактировалось AlexSpl 20 янв 2021, 12:32, всего редактировалось 1 раз.
Вернуться к началу

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

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

Сообщение Rolex » 20 янв 2021, 11:56

Отлично. Спасибо. Я вот думаю насчет этого:
Rolex писал(а):

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

Доступно для найма:
Гномы - 24

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

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

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

Сообщение Rolex » 20 янв 2021, 13:05

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 » 20 янв 2021, 13:09

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

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

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

Сообщение Rolex » 20 янв 2021, 13:18

Это первый варинт без исправления. То есть в первом варианте мы не видим после отказа, но видим после принятия боя, после того как герой игрока сдадится/сбежит не взяв Склеп. С исправлением же мы видим в любом случае независмо от того приняли мы бой или нет.
Последний раз редактировалось Rolex 24 янв 2021, 23:42, всего редактировалось 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 » 20 янв 2021, 13:54

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

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 » 20 янв 2021, 14:17

Цитата:
А вот как быть с внешними жилищами существ. Можно ли их сделать через один лоухук или хайхук (получать имена нужных существ и их кол-во по ПКМ по нужному жилищу), или это придется на каждое жилище существ свой хук делать?

Хук на сообщение по правому клику - универсальный, в нём можно обработать любой объект. А вот на посещение будет два или три дополнительных хука. 1) Для жилищ 1-го уровня, 2) для жилищ, где можно нанять один тип существ за ресурсы, и (возможно) 3) для жилищ, где можно нанимать больше одного типа существ.
Вернуться к началу

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

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

Сообщение Rolex » 20 янв 2021, 14:28

Глянул как сделано в Хота. Сравнил все в сетевой игре в Хота и в Сод с вашим плагином с исправленной showGuards. Там при входе отображается охрана и после посещения и отказа от боя также отображается охрана по ПКМ (за Посещение (Посещено/Не посещено) ничего не пишется). Но при этом в оригинале даже после того как Склеп взяли, всегда вылазит диалог "Хотите обыскать могилы", с возможностью отказатся. Только вот в оригинале охрана не отображается, то есть игрок не знает посещал ли этот Склеп до него кто-то другой и соотв скорей всего будет соглашатся. В случае с Хотой диалог с кол-вом охраны и кнопками Согласия и Отказа отображается до тех пор пока Склеп не взяли. При отказе просто по ПКМ выводится охрана. А вот как только игрок берет Склеп, то при повторном посещении ним или другим игроком диалог с охраной и возможностью отказатся не выводится, чтобы игрок не смог отказатся и сразу получил -1 к Морали ибо охраны нет и она не отобразится.

В нашем же случае получется, что когда Склеп не взят выводится диалог "Хотите обыскать могилы?" и охрана, а когда уже взят, то только диалог, но уже без охраны. Соответственно игроки будут тупо отказыватся, так как будут понимать, что Склеп уже пуст. Поэтому надо бы этот код с обновленной showGuards как-то допилить для Склепа и Кораблей, сделав так, чтобы при посещении игроком уже разграбленного Склепа не выводился диалог без охраны с возможностью отказаться от обыска, а сразу же как в Хота прилетал сюрприз в виде -1 Морали. Как будто бы посещая игрок заведомо дает свое согласие на обыск.

AlexSpl писал(а):

Получается, в оригинале для Склепа (и двух его морских аналогов) посещение засчитывается, только если принять бой.

Если другой игрок в сетевой игре в оригинале c подключенным плагином показа охраны зайдет в уже разрабленный Склеп, охраны не увидит, при посещении и по ПКМ ее уже нет, но сможет отказатся от обыска уже разграбленного Склепа и по ПКМ будет выводится (Посещено), а если отключить плагин показа охраны (чистый оригинал без плагина), то в таком случае увидим (Не посещено). Если же убрать этот диалог, когда Склеп пуст и сразу кидать сюрприз, как будто бы игрок согласился на обыск уже разграбленного Склепа, тогда все будет ок.
Последний раз редактировалось Rolex 25 янв 2021, 08:30, всего редактировалось 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 » 20 янв 2021, 19:48

Насчёт однозначного определения собственного номера игрока. Посмотрел код, который показывает хинты по правому клику игрокам. Думаю, правильно использовать o_GameMgr->GetMeID() вместо o_ActivePlayerID (или o_MeID). Если верить коду, эта функция всегда возвращает именно номер игрока (т.е. наш), играем ли мы синглплеер, хотсит или по сети. o_ActivePlayerID нужно использовать, если мы хотим получить номер игрока, который ходит в данный момент. o_MeID я бы вообще не использовал из-за нюансов в хотсите.

* * *
Вообще, нужно как-нибудь собрать инфу, как получить ту или иную информацию, имея определённый набор данных, в один пост, а не искать её по всему форуму. Например, сижу-туплю, не знаю, как получить _Dwelling_* по _MapItem_* :smile14:
Вернуться к началу

Пред.След.

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

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

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

cron