Current time: 23.04.2024, 04:24 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
Плагины. Обсуждение
» Plugins. Discussion & Questions
Author Message
major Offline

Posts: 132
Post: #631

Не знал, куда написать, сюда или в моддинг.
В общем, никогда не работал с диалогами, и не пойму в чем ошибка. Нужно, чтобы в городе при клике на здание открывался жертвенник.
По аналогии со строением на карте, сделал такой код.
Code:
int player_id = o_GameMgr->GetMeID(); // текущий игрок
_Dlg_* dlg = (_Dlg_*)(DwordAt(c->ebp) - 0x370); // ?
CALL_3(int, __thiscall, 0x560060, dlg, &o_GameMgr->hero[town->down_hero_id], player_id); // загрузка диалога
CALL_3(void, __thiscall, 0x5FF800, dlg, -1, -1); // центрирование диалога
CALL_2(int, __thiscall, 0x565640, dlg, 0); // показ диалога
CALL_1(int, __thiscall, 0x562630, dlg); // уничтожение диалога
CALL_1(void, __thiscall, 0x5D5810, o_TownMgr); // обновление экрана города

Код работает, диалог показывается, жертвенник работает. Но при закрытии диалога происходит краш с ошибкой в Wog native dialogs:
Code:
Failed to read data at A.
EIP: Wog native dialogs.1358D (?_Copy@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IAEXII@Z + 221). Code: C0000005

> Registers
EAX: 00000001 (int: 1)
ECX: 02D39AEC (int: 47422188, pint: 0x02D39F10 = 47423248)
EDC: 0EE6B100 (int: 249999616, pint: 0x0EEC36F8 = 250361592)
EBX: 00000001 (int: 1)
ESP: 02D3980C (int: 47421452, pint: 0x00000001)
EBP: 02D398D8 (int: 47421656, pint: 0x0D6142A3 = 224477859)
ESI: 00007801 (int: 30721)
EDI: 0000000A (int: 10)

Соответственно, без этого плагина краша нет, все работает.
31.01.2024 17:06
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2270
Post: #632

(31.01.2024 17:06)major Wrote:  Код работает, диалог показывается, жертвенник работает. Но при закрытии диалога происходит краш с ошибкой в Wog native dialogs:

Под жертвенный алтарь нужно выделять стековую память, если её не выделить - используется первая попавшаяся с затиранием данных в ней, в данном случае - затираются какие-то данные Wog native dialogs. В Вашей команде там стоит знак вопроса - память на функцию Вы подаёте, но не понимаете какую. В ERA+ жертвенный алтарь открывается в Причале, что ещё нужно? При этом вся функция - ассемблерная, без СИ, в оригинале, с которого копируется код, так же ассемблер (я тупо скопировал и не вдавался в подробности), как это должно быть на СИ - х.з.

(31.01.2024 17:06)major Wrote:  CALL_3(void, __thiscall, 0x5FF800, dlg, -1, -1); // центрирование диалога

Эта команда - для карты приключений. При вызове из диалога города она не требуется.

(31.01.2024 17:06)major Wrote:  int player_id = o_GameMgr->GetMeID(); // текущий игрок
_Dlg_* dlg = (_Dlg_*)(DwordAt(c->ebp) - 0x370); // ?
CALL_3(int, __thiscall, 0x560060, dlg, &o_GameMgr->hero[town->down_hero_id], player_id); // загрузка диалога

Начало функции неправильное. Для получения игрока - используйте содовскую функцию, а для армии героя - проверяйте героя на null, т.к. героя может не быть (он в городе в 2-х местах) - выводите сообщение без вызова диалога жертвенного алтаря.
(This post was last modified: 31.01.2024 23:31 by XEPOMAHT.)
31.01.2024 23:15
Find all posts by this user Quote this message in a reply
major Offline

Posts: 132
Post: #633

(31.01.2024 23:15)XEPOMAHT Wrote:  Под жертвенный алтарь нужно выделять стековую память, если её не выделить - используется первая попавшаяся с затиранием данных в ней, в данном случае - затираются какие-то данные Wog native dialogs. В Вашей команде там стоит знак вопроса - память на функцию Вы подаёте, но не понимаете какую. В ERA+ жертвенный алтарь открывается в Причале, что ещё нужно? При этом вся функция - ассемблерная, без СИ, в оригинале, с которого копируется код, так же ассемблер (я тупо скопировал и не вдавался в подробности), как это должно быть на СИ - х.з.
Я поэтому и хочу понять, как с этим работать. Смотрел код в Соде, смотрел код в Тифоне, - практически одинаковые. Понимаю, что память надо выделить, но сколько? Как это определить?
Сейчас попробовал сделать так, и вроде не крашится.
Code:
_Dlg_* dlg = (_Dlg_*)o_New(600);

(31.01.2024 23:15)XEPOMAHT Wrote:  Эта команда - для карты приключений. При вызове из диалога города она не требуется.
Без этой команды диалог расположен левее и выше экрана города. А так четко по центру.

(31.01.2024 23:15)XEPOMAHT Wrote:  Начало функции неправильное. Для получения игрока - используйте содовскую функцию, а для армии героя - проверяйте героя на null, т.к. героя может не быть (он в городе в 2-х местах) - выводите сообщение без вызова диалога жертвенного алтаря.
Там содовская функция 0x4CE6E0 используется. И все проверки на наличие героя, конечно, есть.

В общем пока что игра не крашилась, но я не исключаю рандомные краши. Поэтому вопрос актуальный, как правильно это сделать, и как узнать, сколько памяти выделять?
01.02.2024 03:13
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2270
Post: #634

(01.02.2024 03:13)major Wrote:  Я поэтому и хочу понять, как с этим работать. Смотрел код в Соде, смотрел код в Тифоне, - практически одинаковые. Понимаю, что память надо выделить, но сколько? Как это определить?

Столько же, сколько и выделяет СоД - 968 байт. На СИ непонятно как вручную выделяется стековая память - это делает компилятор автоматически (СИ - высокоуровневый язык и не разрешает работать со стеком напрямую).

(01.02.2024 03:13)major Wrote:  Без этой команды диалог расположен левее и выше экрана города. А так четко по центру.

Странно, я разницы не заметил. Тогда раскоментирую её в Тифоне.

(01.02.2024 03:13)major Wrote:  Там содовская функция 0x4CE6E0 используется. И все проверки на наличие героя, конечно, есть.

В твоем коде не заметил. СИ тяжело читать.

(01.02.2024 03:13)major Wrote:  Поэтому вопрос актуальный, как правильно это сделать, и как узнать, сколько памяти выделять?

Этот диалог нестандартный, там надо смотреть на количество памяти, которое выделяет СоД. Как правильно написать на СИ - сложно сказать. У тебя в коде только 1 строчка высокоуровневая (как раз которую я не смог понять), остальное - низкоуровневое, поэтому смысл использовать СИ? Проще поставить ассемблерную вставку и не мучиться, т.к. у тебя копируется ассемблерный код, восстановить который корректно на СИ может только профессиональный программист.
01.02.2024 06:48
Find all posts by this user Quote this message in a reply
igrik Offline
Administrators

Posts: 2814
Post: #635

(31.01.2024 17:06)major Wrote:  Не знал, куда написать, сюда или в моддинг.
В общем, никогда не работал с диалогами, и не пойму в чем ошибка. Нужно, чтобы в городе при клике на здание открывался жертвенник.
По аналогии со строением на карте, сделал такой код.
Code:
int player_id = o_GameMgr->GetMeID(); // текущий игрок
_Dlg_* dlg = (_Dlg_*)(DwordAt(c->ebp) - 0x370); // ?
CALL_3(int, __thiscall, 0x560060, dlg, &o_GameMgr->hero[town->down_hero_id], player_id); // загрузка диалога
CALL_3(void, __thiscall, 0x5FF800, dlg, -1, -1); // центрирование диалога
CALL_2(int, __thiscall, 0x565640, dlg, 0); // показ диалога
CALL_1(int, __thiscall, 0x562630, dlg); // уничтожение диалога
CALL_1(void, __thiscall, 0x5D5810, o_TownMgr); // обновление экрана города

Код работает, диалог показывается, жертвенник работает. Но при закрытии диалога происходит краш с ошибкой в Wog native dialogs. Соответственно, без этого плагина краша нет, все работает.
Очень странно. Вообще не понятно, причём здесь WND. Покажи весь код плагина, чтобы я мог дома проверить и определить почему.

(31.01.2024 17:06)major Wrote:  Без этой команды диалог расположен левее и выше экрана города. А так четко по центру.
Это проверялось с HD модом? Значит без этой команды HD не проверяет на центр экрана, и диалог рисуется в центре игры без учёта HD разрешения игры.


game bug fixes extended.dll || My Plugins || My GitHub
01.02.2024 11:59
Visit this user's website Find all posts by this user Quote this message in a reply
major Offline

Posts: 132
Post: #636

(01.02.2024 11:59)igrik Wrote:  Очень странно. Вообще не понятно, причём здесь WND. Покажи весь код плагина, чтобы я мог дома проверить и определить почему.
Вот.
Code:
int __stdcall Town_Dialog_Unique_Dwelling_4(LoHook* h, HookContext* c)
{
    _Town_* town = (_Town_*)c->ecx;

    // Если нажата правая кнопка мыши.
    if (IntAt(c->ebp + 8))
    {
        // Переходим к функции показа сообщения.
        c->return_address = 0x5D4353;
        return NO_EXEC_DEFAULT;
    }

    // Возврат по умолчанию - показ сообщения по ЛКМ.
    c->return_address = 0x5D4077;

    // Если Некрополис.
    if (town->type == TID_NECROPOLIS)
    {
        // Переходим к Трансформатору нежити.
        c->return_address = 0x5D3FCE;
    }
    // Если Причал.
    else if (town->type == TID_COVE)
    {
        // Устанавливаем возврат на выход из функции.
        c->return_address = 0x5D4617;

        // Если в гарнизоне никого.
        if (town->down_hero_id == -1)
        {
            // Записываем сообщение в буфер.
            sprintf(o_TextBuffer, o_GENRLTXT_TXT->GetString(274), (char*)CALL_2(int, __fastcall, 0x460CC0, TID_COVE, TBI_UNIQUE_4));
            // Выводим сообщение о героях-гостях.
            CALL_12(void, __fastcall, 0x4F6C00, o_TextBuffer, 1, -1, -1, -1, -1, -1, 0, -1, 0, -1, 0);
        }
        // Иначе.
        else
        {
            // Получаем текущего игрока.
            int player_id = o_GameMgr->GetMeID();
            // Выделяем память под диалог.
            _Dlg_* dlg = (_Dlg_*)(DwordAt(c->ebp) - 0x370);
            // Загружаем диалог.
            CALL_3(int, __thiscall, 0x560060, dlg, &o_GameMgr->hero[town->down_hero_id], player_id);
            // Располагаем его по центру.
            CALL_3(void, __thiscall, 0x5FF800, dlg, -1, -1);
            // Выводим диалог на экран.
            CALL_2(int, __thiscall, 0x565640, dlg, 0);
            // Уничтожаем диалог.
            CALL_1(int, __thiscall, 0x562630, dlg);
            // Обновляем экран города.
            CALL_1(void, __thiscall, 0x5D5810, o_TownMgr);
        }
    }
    
    return NO_EXEC_DEFAULT;
}
Code:
_PI->WriteLoHook(0x5D4055, Town_Dialog_Unique_Dwelling_4);

(01.02.2024 11:59)igrik Wrote:  Это проверялось с HD модом? Значит без этой команды HD не проверяет на центр экрана, и диалог рисуется в центре игры без учёта HD разрешения игры.
Да, с HD модом. Вот так оно выглядит без центровки.

Image: grotto.png
01.02.2024 14:28
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2270
Post: #637

(01.02.2024 14:28)major Wrote:  
Code:
_PI->WriteLoHook(0x5D4055, Town_Dialog_Unique_Dwelling_4);

Этот хук весь кейс кликов по типу специальных объектов 4 в ERA+ подменит. При этом в подменном коде самого кейса у Вас нет (с проверками код работает медленнее) и адреса выходов не совпадают с теми, что должны быть в кейсе:

Code:
Адреса_кликов_в_экране_города_Special4 = $
dd 5D406Ch ; Замок - Святой Источник (сообщение)
dd 5D4617h ; Оплот - ничего (пустой клик)
dd 5D406Ch ; Башня - Стена Знаний (сообщение)
dd 5D406Ch ; Инферно - Культ Огня (сообщение)
dd Подготовить_некротрон ; Некрополис - Некротрон (открывает преобразователь нежити)
dd 5D406Ch ; Темница - Академия Боевых Искусств (сообщение)
dd 5D406Ch ; Цитадель - Чертоги Вальгаллы (сообщение)
dd 5D406Ch ; Крепость - Водяное Колесо (сообщение)
dd 5D4617h ; Сопряжение - ничего (пустой клик)
dd WoG_Клик_в_окне_города.открыть_окно_жертвенного_алтаря ; Причал - Грот (открывает жертвенный алтарь)
dd 5D406Ch ; Фордж - Дубликатор (сообщение)
dd 5D406Ch ; Бастион - Самум (сообщение)

Зачем переписываете на СИ то, что и так сделано в ERA+? Там тонна несделанных вещей болтается, те же здания Форджа/Бастоина могли запрограммировать, т.к. Причал давным давно полностью реализован на Ассемблере. Stop
01.02.2024 14:50
Find all posts by this user Quote this message in a reply
major Offline

Posts: 132
Post: #638

(01.02.2024 14:50)XEPOMAHT Wrote:  Этот хук весь кейс кликов по типу специальных объектов 4 в ERA+ подменит. При этом в подменном коде самого кейса у Вас нет (с проверками код работает медленнее) и адреса выходов не совпадают с теми, что должны быть в кейсе:
Ну скорость работы мне абсолютно не важна, так как разницы у себя я не замечаю, и мод делаю исключительно для себя. А так как для почти всех городов результат один - показ сообщения - решил не использовать свитч, дабы не перечислять все города. Ну и к тому же, если вдруг когда-нибудь будет еще один город, его в свитч добавлять не надо будет, так как по умолчанию показывается стандартное сообщение.
Адреса выходов не совпадают, так как после проверки города, идет проверка на нажатие ПКМ. У меня же проверка на нажатие ПКМ вынесена ранее. Сделал так для того, чтобы Некротрон и Грот не открывались на нажатие ПКМ.

(01.02.2024 14:50)XEPOMAHT Wrote:  Зачем переписываете на СИ то, что и так сделано в ERA+? Там тонна несделанных вещей болтается, те же здания Форджа/Бастоина могли запрограммировать, т.к. Причал давным давно полностью реализован на Ассемблере. Stop
Основная причина здесь из-за Некротрона (и Преобразователя), которые подменяли некоторых существ в таблице Трансформации на личей и скелетов, не зависимо от их изначальной установки в Тифоне. У меня для него другое свойство.
01.02.2024 15:53
Find all posts by this user Quote this message in a reply
igrik Offline
Administrators

Posts: 2814
Post: #639

(31.01.2024 08:36)Archer30 Wrote:  igrik, I'd like to report my findings of Spell Description Mod

1. The hint of Pitlord's number of resurrections is incorrect.
In this battle, I tried to revive a dead pikemen stack of 11, the hint shows a huge number instead of the correct amount.
This issue can be reproduced in a new game.
Fixed!
You can fix the error in the text file yourself. Replace %d with %s
Image: image.png

(31.01.2024 08:36)Archer30 Wrote:  2. Potential crash when AI resurrect with Pitlord's spell.
I am not entirely sure this is spell description related, but the address of the crash hints it could be.
In the save game, when Tazar initiates a battle with Pit Lords and spams Death Ripple to kill the extra stacks spawned by "Karmic Battle" (option 38), there is a chance the crash when Pitlords resurrect the killed allies.
Again this crash is only reproducible with a low chance. I just report here in case it's useful to improve the plugin if it turns out to be related.
I do not know what the mistake is. But it's not about the plugin.


game bug fixes extended.dll || My Plugins || My GitHub
01.02.2024 18:09
Visit this user's website Find all posts by this user Quote this message in a reply
igrik Offline
Administrators

Posts: 2814
Post: #640

(01.02.2024 03:13)major Wrote:  В общем пока что игра не крашилась, но я не исключаю рандомные краши. Поэтому вопрос актуальный, как правильно это сделать, и как узнать, сколько памяти выделять?
Code:
int player_id = o_GameMgr->GetMeID();
// выделяем память под диалог (600 байт, см.0x5601D0)
_int_ dlg = o_New(600);
// конструктор диалога
CALL_3(int, __thiscall, 0x560060, dlg, &o_GameMgr->hero[town->down_hero_id], player_id);
// Располагаем диалог по центру.
CALL_3(void, __thiscall, 0x5FF800, dlg, -1, -1);
// запускаем диалог
CALL_2(int, __thiscall, 0x565640, dlg, 0);
// Уничтожаем диалог.
CALL_1(int, __thiscall, 0x562630, dlg);
// очищаем память диалога
o_Delete(dlg);
// Обновляем экран города.
CALL_1(void, __thiscall, 0x5D5810, o_TownMgr);


game bug fixes extended.dll || My Plugins || My GitHub
01.02.2024 18:44
Visit this user's website Find all posts by this user Quote this message in a reply
Archer30 Offline
Moderators

Posts: 1117
Post: #641

igrik, thank you!


Latest ERA mods and scripts in development - My GitHub
02.02.2024 01:45
Find all posts by this user Quote this message in a reply
major Offline

Posts: 132
Post: #642

Вопрос по плагину NPC_Skills_Scrolling.dll.
У меня он ни в какую не хочет запускаться, при построении диалога командира игра крашится, так как в ecx не попадает структура командира.

Code:
HOMM3 HD version: 5.4 R29
Time {   13.02.2024    09:45:22 }

GUN:  [ZZ79779073039T645247MVGZX HHW 039TY]

Exception
{
   Module:     NPC_Skills_Scrolling.dll
   Adress:      [ NPC_Skills_Scrolling.dll+0x1E4B ]
   Code:        EXCEPTION_ACCESS_VIOLATION
   Flags:       0x00000000
   Information: read of address: 0x00000120
}

Context { EAX: 0x00000000, ECX: 0x00000000, EDX: 0x00000000, EBX: 0x00000268, ESP: 0x02D398B4, EBP: 0x02D398DC, ESI: 0x0C73AEF0, EDI: 0x0C73AF20 }

Call stack
{
                           ? called from before    [ 0x0000001C ]
                           ? called from before    [ 0x0C73AEF0 ]
}

Полагаю, что проблема, или не проблема, вот здесь. Структура npc забита нулями.
Code:
int __stdcall Before_WndNPC_DLG(LoHook* h, HookContext* c) //before dlg run
{

    _DlgNPC_* npcDlg = o_dlgNPC;
    _Npc_* npc = (_Npc_*)o_dlgNPC->DlgTop;

    HDDlg* dlg = (HDDlg*)c->esi;

    GetNpcSSkills(npc); // place new skills into vector
    ...
}

Сначала думал, что проблема в ERA+. Но в итоге оставил в list.txt такой набор модов, и игра всё равно крашится.
Code:
WoG
WoG Rus

Сборка Эра+ от Панды. Версия Эры 3.9.1. WND присутствует.

P.S. Опытным путём выяснил, что замена папки WoG из Лаунчера решает проблему. Копаю дальше.

P.P.S. В общем отбой, у меня оказалась немного более старая версия WND, с ней игра крашится. С новой всё ок.
(This post was last modified: 09.02.2024 09:15 by major.)
09.02.2024 07:02
Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2270
Post: #643

igrik, по какому принципу wog_native_dialogs.era решает, отрисовывать эти кнопки или нет? Т.к. при вызове диалога из главного меню игры, кнопки на форму не ставятся:

Image: image.jpg
10.02.2024 23:06
Find all posts by this user Quote this message in a reply
igrik Offline
Administrators

Posts: 2814
Post: #644

(10.02.2024 23:06)XEPOMAHT Wrote:  igrik, по какому принципу wog_native_dialogs.era решает, отрисовывать эти кнопки или нет? Т.к. при вызове диалога из главного меню игры, кнопки на форму не ставятся:

Заполнение состояния кнопок просходит в функции BuildAll 0x7787CE (wogsetup.cpp в исходниках WOG).
Как именно - я уже не и помню. Но в этот механизм я не лез. Тут всё делает сам Вог

Я читаю состояне из _DlgSetup->ButtonsStates[номер_кнопки (Click to View)
Описание структуры в исходниках WOG (classes.h) (Click to View)


game bug fixes extended.dll || My Plugins || My GitHub
11.02.2024 04:51
Visit this user's website Find all posts by this user Quote this message in a reply
XEPOMAHT Offline
Moderators

Posts: 2270
Post: #645

(11.02.2024 04:51)igrik Wrote:  Заполнение состояния кнопок просходит в функции BuildAll 0x7787CE (wogsetup.cpp в исходниках WOG).
Как именно - я уже не и помню. Но в этот механизм я не лез. Тут всё делает сам Вог

Спасибо за подсказку. Нашёл воговский кастыль:

Code:
// поддержка режима редактирования опций ВоГификации
    //{0x4EF3A0,0x0,DP(GoToNewGameScreen)}, // * new setup now

который как раз и активирует эти кнопки. Опять придётся переписывать воговский код, чтобы избавиться от кастылей (и заодно поставить кнопку и реакцию на неё вместо кастыльного кода, проверяющего координаты нажатия вместо индекса нажатой кнопки).
11.02.2024 06:58
Find all posts by this user Quote this message in a reply
« Next Oldest | Next Newest »
Post Reply 


Forum Jump:

Powered by MyBB Copyright © 2002-2024 MyBB Group