Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Обсуждение инженерного анализа
DF2 :: ФОРУМЫ > Игровые форумы > Heroes of Might & Magic III > Моды
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9
Richter
Глаза буквально смозолил в Иде уже, пытаясь найти куда поставить хук, чтобы окно героя закрывалось. Смысл в том, что необходимо чтобы при клике мышью (или другом действии) обновить изображение HEROSCR4.pcx.
Может для этого и не нужно закрывать окно героя. Наверно нужно как то "перевызвать", что ли Dl_hero_info или типа того. Подставить картинку сумею сам.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Igrik, сможете глянуть, как сделать кнопку "уволить героя" не активной?
igrik
в каком смысле обновить HEROSCR4.pcx? Это же просто задник и что коммандна UN:R3/-1; не подходит?
Опиши в деталях что ты хочешь
Barin
Цитата
Заменить деф у героя в бою.

Код
!?BA0;
!!UN:C6919200/4/?y10;
!!VRy51:S0 *4 +y10 +21508; (0 - левый, 1 - правый)
!!UN:Cy51/4/?y52;

!!SN:E5622208/2/^ch17.def^; (таки имя дефа)
!!UN:Cy51/4/v1;

!!UN:Cy52/4/?y53;
!!VRy53:+4;
!!UN:Cy53/4/?y54;
!!SN:Ey54/2/y52;


Таки да, можно делать героев с уникальными боевыми моделями.


Попробовал, не работает в Эре. Версия 2.4. Где ошибка?
feanor
Триггер не тот. BF можно, например.
Richter
Цитата(igrik @ 10 Nov 2015, 18:33) *
в каком смысле обновить HEROSCR4.pcx? Это же просто задник и что коммандна UN:R3/-1; не подходит?
Опиши в деталях что ты хочешь

Когда находишься в окне героя, и хочешь посмотреть другого героя через панель справа. Нажимая на этот box с другим героем, менялся и задник диалога. Посмотрел в иде. Там функция построения информации о диалоге перед показом, но видимо работает она только перед показом диалога. Пробовал через ERM через кнопку hsbtns.def Заменяя последнюю цифру в картинке (через адрес) работает. Т.е. через CM, нажал на 30720 закрылся диалог, появился новый. Пробовал через доп.кнопку с такими же параметрами- не работает.
MasterOfPuppets
Короче, смотришь функцию обновления окна героя (4E1CC0, емнип). Находишь в ней обновление нужного тебе элемента по ID - и чудишь, если навыки позволяют. Если его обновление не прописано в функции - придется самому прописать. Можно вообще HEROSCR4.pcx превратить в HEROSCR4.def и в зависимости от героя менять номер кадра.
Richter
Цитата(MasterOfPuppets @ 12 Nov 2015, 13:21) *
Короче, смотришь функцию обновления окна героя (4E1CC0, емнип). Находишь в ней обновление нужного тебе элемента по ID - и чудишь, если навыки позволяют. Если его обновление не прописано в функции - придется самому прописать. Можно вообще HEROSCR4.pcx превратить в HEROSCR4.def и в зависимости от героя менять номер кадра.

...ммм Это нужно динамическую библиотеку написать для получения таких результатов или в самой программе. Я пока застрял на регистре eax в изучении ассемблера.
Круто. Особенно в def превратить. Вчера только смотрел и думал об этом. За обработку def'а другие функции отвечают вроде. Мне такое не потянуть. Спасибо.
feanor
Цитата
Окна найма существ/боевых машин героем
Вах. Одын вопрос: использовать для временных переменных v-шки обязательно, а то я бы на y заменил (с коррекцией адреса, понятно)?
igrik
нет не обязательно. Я просто знал адрес v переменных, поэтому их и использовал. С y переменными тоже работало, но я не был уверен в надежности, т.к. не знал точных их адресов. Вообще там нужно просто указать ссылку на адрес, в котором указано количество монстров для найма. И размер по непроверенным данным 2 байта

Цитата
менялся и задник диалога.

Да ппц. Как может меняться задник диалога? это же статическое изображение "HEROSCR4.pcx". Как оно может меняться в процессе игры. Или тогда что в твоем понимании "задник диалога". Такое ощущение, что ты говоришь о изменении отображения артов, навыков, монстров и т.п. Так это не задник! если хочешь поменять "HEROSCR4.pcx" то используй !!SN:L^Era.dll^/?y1 Ay1/^RedirectFile^/?y2 Ey2/1/^HEROSCR4.pcx^/^anyfuckingdef.pcx^;
Richter
Цитата
менялся и задник диалога.
Да ппц. Как может меняться задник диалога? это же статическое изображение "HEROSCR4.pcx". Как оно может меняться в процессе игры. Или тогда что в твоем понимании "задник диалога". Такое ощущение, что ты говоришь о изменении отображения артов, навыков, монстров и т.п. Так это не задник!

нет, нет...
мне не менять надо. Мне нужно закрыть диалог героя, по требованию, что называется, остальное сам смогу.
Цитата(MasterOfPuppets @ 12 Nov 2015, 13:21) *
Короче, смотришь функцию обновления окна героя (4E1CC0, емнип). Находишь в ней обновление нужного тебе элемента по ID - и чудишь, если навыки позволяют. Если его обновление не прописано в функции - придется самому прописать. Можно вообще HEROSCR4.pcx превратить в HEROSCR4.def и в зависимости от героя менять номер кадра.

MoР понял меня.
MasterOfPuppets
Создать новый ID с той же картинкой, который будет идти в отрисовке сразу после задника, а в функции обновления - первым. Делов-то. И не надо закрывать окно героя. Это костыль, который вызовет раздражающее моргание.
Если с костылем - то иди по адресу 4DEA6Ah. Там проверка на RoE, если она - то вместо heroscr4.pcx отображается heroscr3.pcx. Ставь хук и вводи свои условия.
Richter
Цитата(MasterOfPuppets @ 12 Nov 2015, 15:18) *
Создать новый ID с той же картинкой, который будет идти в отрисовке сразу после задника, а в функции обновления - первым. Делов-то. И не надо закрывать окно героя. ... ....

Это ещё раз доказывает, что всё гениальное просто! В моём моде уже есть такое "наложение". ... блин, как же я не догадался.
Richter
С Наложением ID не очень качественно выходит. Id приходится все равно закрывать, прежде чем открыть диалог другого героя. idontno.gif
MasterOfPuppets
Поясни, как ты сделал.
Richter
Сделал ID вызываемый через Box'ы героев (панель справа). Триггер !?CM2. Всё прозрачное, кроме того что нужно. Задача № 1 образовалась -
Клик по box"у с героем, ID закрылся, нужно делать ещё один клик, чтобы активировать. Можно конечно Через !!SN:E(4E1A70h не помню точно)/2... Но это открытие нескольких диалогов, которые закрывать всё равно придется. Некрасиво, мягко говоря.
... пока вот так.
igrik
feanor, можешь выложить пример создания *.dll/*.era (с учетом понятия "для чайника") или через патчер х86.
Нужно просто вызвать функцию FU77012 по адресу 0х464F9C (место автокаста заклинаний от артов). ERM хукер не камильфо
feanor
Цитата(igrik @ 19 Nov 2015, 12:25) *
feanor, можешь выложить пример создания *.dll/*.era (с учетом понятия "для чайника") или через патчер х86.
Нужно просто вызвать функцию FU77012 по адресу 0х464F9C (место автокаста заклинаний от артов). ERM хукер не камильфо

И ты, Брут?(с)

Среда какая? Или со среды и начинать?
igrik
Точно, не туда запостил fp3.gif
На Вогфоруме было, но он лежит зараза и не думает вставать.
Со среды и начать)) Лучше же конечно через патчер, но впринципе без разницы
feanor
Ну, окей.

Качаем, например, с целью ознакомления триалку Visual Studio 2008, ставим (дело долгое, часа этак два, запускаем).
Почему восьмая? Потому что, например, неко-торые хэдеры сделаны под студию (gcc-based IDE типа кодблокса раньше чуть давились), а дллки из-под двенадцатой студии что-то с собой тянут и на некоторых машинах не идут.
Хотя хз, короч.

Запускаем.
Файл => Создать => Проект. Да, у меня богомерзкая локализованная.



Окей. Запускается мастер.



Далее. Выбираем DLL.



Готово. Открывается проект. Кликаем на dllmain.cpp




DllMain - точка старта, запускаемая в перечисленных ниже случаях, подключении-отключении процесса, подключении-отключении в поток, в общем, можно почитать на MSDN.
Нас интересует чистый старт (DLL_PROCESS_ATTACH). Но перед тем как стереть все к чертовой матери, нужно (хотя и не обязательно) отключить предкомпилированные заголовки.

Это такая сомнительная фича, которая сделана для ускорения компиляции кода. Другое дело, что она заодно превращает деревья инклудов в труднопредсказуемую лапшу. Хм. В общем, отключаем.



С/С++ -> Предварительно скомпилированные заголовки.



Переключаем конфигурации на "Все", выставляем "Не использовать предварительно скомпилированные заголовки".



Окей. Теперь время ВЫРЕЗАТЬ ВЫРЕЗАТЬ ВЫРЕЗАТЬ ВЫРЕЗАТЬ.
Можно выпилить stdafx.h и stdafx.cpp (и их упоминания в инклудах), но это не так важно уже.

Заменяем код в dllmain.cpp на

Код
#include <windows.h>
#include <stdio.h>
#include "..\..\include\era.h"
#include "..\..\include\patcher_x86_commented.hpp"


Patcher * globalPatcher;
PatcherInstance *patcher;


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        globalPatcher = GetPatcher();
        patcher =  globalPatcher->CreateInstance("itsmustbeveryuniuename");

        ConnectEra();

    }
    return TRUE;
}


Ну, пути к инклудам - свои: у меня инклуды лежат на одном уровне с папками проектов.
Создаем и инициализируем объект патчера, коннектимся к Эре.

Пишем хук.

В DllMain, ставим хук:

Код
patcher->WriteLoHook(0x464F9C, (void*)hook_464F9C);

LoHook - низкоуровневый ход, предназначенный для мелких правок уровнем чуть выше ассемблера. При активном использовании начисто лишает шансов разобраться, что ваще происходит на пытаемом участке.
Есть еще HiHook, служит для перехвата вызовов функций.
много что еще есть, лучше посмотреть в прекрасно документированном заголовочнике.

перед DllMain создаем функцию хука:

Цитата
int __stdcall hook_464F9C(LoHook* h, HookContext* c)
{
FireErmEvent(77012);
return EXEC_DEFAULT;
}

FireErmEvent- эрошная функция. EXEC_DEFAULT - выполнить затертый хуком код.
Из с можно выдрать, например, значения регистров, если надо.

Таким образом, код сейчас выглядит так:



Компилируем (F5 или кнопка с зеленой стрелочкой, стоит переключиться перед этим в Release)



Появляется окно с предложением приаттачиться к процессу, отказываемся.
Наша длл лежит в <project_name>/release/Test.dll

все, кладем, тестируем (я не гонял, ага)

скачать:
https://dl.dropboxusercontent.com/u/61759222/HoMM/fish.zip
igrik
А может не билдится, потому что не указаны инклуды патчера x86? а то у меня их нету, и опять млин мертвый вогфорум с этими исходниками((
feanor
Эм, что не билдится?
если чо, прост распакуй рыбу, ребилдни и попробуй скомпилить
igrik

А как распаковать рыбу?

Код
#include <windows.h>
#include <stdio.h>
#include "..\..\Era\era.h"


Patcher * globalPatcher;
PatcherInstance *patcher;


int __stdcall hook_464FBA(LoHook* h, HookContext* c)
{
FireErmEvent(880001);
return EXEC_DEFAULT;
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        globalPatcher = GetPatcher();
        patcher =  globalPatcher->CreateInstance("Poker");

        ConnectEra();

        patcher->WriteLoHook(0x464FBA, (void*)hook_464FBA);

    }
    return TRUE;
}
feanor
Ошибки-то какие?
igrik
feanor
Эм, а сама-то дллка создается?
И да, инклуд патчера куда подевался?

Цитата
А как распаковать рыбу?
Винраром, полагаю я.
Цитата
igrik
На счет рыбы затупил))
Получилось!! Огромное спасибо!!!
feanor
Цитата
Successful
igrik
Цитата(Algor @ 21 Nov 2015, 08:32) *
igrik, а можно допилить, чтобы еще и уровень (нет...эксперт) каста задавать?
И силу(длительность). И сторону (левый/правый/обе/поле?/целевой гекс?).
С заклинаниями урона работает, кстати? А с минами/зыбучими песками?

Algor, слишком сложно реализовать все хотелки, ибо нюансов тут масса.
Ты лучше ее потестируй и запили в нужном для тебя контексте.
Но если вкратце, то основная команда:
Код
!!UN:C6919200/4/?y1;
!!SN:E5898560/2/y1/x1/-1/2/-1/3/50;

Сторону выбрать ты не можешь. Заклинание кастуется только активной стороной (и если это дружественное, то на себя и т.п.).
Собственно !!SN:E5898560/2/y1/x1/x2/x3/x4/x5/x6 это функция каста закла, где:
y1 - это комбат менеджер (его мы не трогаем и оставляем как есть)
x1 - номер закла (очень важна связка с x2, иначе вылеты), если целевое заклинание, то обязательно в x2 номер цели
x2 - целевой стек (важно чтобы там был стек монстра), либо если массоввый закл (-1) /либо поле, но я не тестировал на этом/
x3 - кто кастует и описалово как в !!MM: 0 - герой (c вычетом маны и невозможностью каста в этом раунде битвы), 1 - монстр, 2 - арт (зачастую "что попало" в !!MM), 3 - герой (без вычета маны), 4 - герой (без вычета маны + бистро бистро анимация)
x4 - тут если НЕ стоит -1, то это становится целевй стек, а на позиции x2 проигрывается анимация "волшебное зеркало"
x5 - собственно уровень навыка (нет...эксперт)
x6 - длительность/сила
Минное поле/ зыбучие пески работают как массовый закл c x2=-1. Армагеддон тоже массовый.
Ударные заклинания работают: у меня лазурный перед ударом бил взрывом
Если в x3=1 (монстр), то полет заклинания происходит от позиции данного стека. Походу через эту функцию запилили атаку Санта-гремлинов.
Richter
Здравствуйте все! Задача у меня назрела следующая:
Понадобилось разместить def файл в окне героя, с управлением под "началом" ERM (тобишь регулировать показ номера кадра) с координатами (x,y) размером выше 1 байта.
Думалось поначалу через Olly переписать ID (110) показа слова "Журнал" в окне героя. Ничего не вышло. Нужно допом что то писать похоже, чтобы вклиниться.
Может ZGODBON.DEF задействовать, но где его функция. Несмог найти. Есть у кого интерес?
igrik
Не уверен, но попробуй через добавление новой кнопки + эта функция
Код
!!UN:C10916496/4/?y1;
!!if&y1>0:;
  !!SN:L^Era.dll^/?y2 Ay2/^GetButtonID^/?y3 Ey3/0/^название основной кнопки (без расширения def)^;  !!VRy4:Sv1;
  !!SN:E6288384/2/y1/512/9/y4/z1;
  !!SN:E6288384/2/y1/512/2/y4/0;
  !!SN:E6288528/2/y1/6/16384;
  !!SN:E6288816/2/y1/6;
!!en:;

в z1 должно лежать название дефа кнопки которую нужно отобразить
Richter
Цитата(igrik @ 05 Dec 2015, 16:23) *
Код
!!UN:C10916496/4/?y1;
!!if&y1>0:;
  !!SN:L^Era.dll^/?y2 Ay2/^GetButtonID^/?y3 Ey3/0/^название основной кнопки (без расширения def)^;  !!VRy4:Sv1;
  !!SN:E6288384/2/y1/512/9/y4/z1;
  !!SN:E6288384/2/y1/512/2/y4/0;
  !!SN:E6288528/2/y1/6/16384;
  !!SN:E6288816/2/y1/6;
!!en:;

в z1 должно лежать название дефа кнопки которую нужно отобразить

Не совсем понял как реализовать контроль за кадром, сделал так.
!?FU5212225;
!!VRz477:S^Butst1.def^;
!!UN:C10916496/4/?y1;
!!if&y1>0:;
!!SN:L^Era.dll^/?y2 Ay2/^GetButtonID^/?y3 Ey3/0/^Butst1^; !!VRy4:Sv1;
!!SN:E6288384/2/y1/512/9/y4/z477;
!!SN:E6288384/2/y1/512/2/y4/0;
!!SN:E6288528/2/y1/6/16384;
!!SN:E6288816/2/y1/6;
!!en:;
!?CM2;
!!CM:I?y5 F?y6;
!!FU5212225&y5=0/y6=512:P; Вызов функции по ПКМ на условном месте 0.


Пишет ошибка синтаксиса: Ey3/0/^Butst1^;
P.S.
текстовик для кнопок и dll'ка на своих местах.
igrik
в z477 - название кнопки, которую хочешь там видеть
Ey3/0/^название основной кнопки^ - оно не изменно, и должно быть прописано у тебя в button.btn.
А ты название новой впилил зачем то в "Ey3/0/^название основной кнопки^"

Например. Старая кнопка называется Butst1, а новая Butst2. Тогда код будет примерно таким
Код
!!VRz477:S^Butst2.def^;
!!FU1:P;

!?FU1;
!!UN:C10916496/4/?y1;
!!if&y1>0:;
!!SN:L^Era.dll^/?y2 Ay2/^GetButtonID^/?y3 Ey3/0/^Butst1^; !!VRy4:Sv1;
!!SN:E6288384/2/y1/512/9/y4/z477;
!!SN:E6288384/2/y1/512/2/y4/0;
!!SN:E6288528/2/y1/6/16384;
!!SN:E6288816/2/y1/6;
!!en:;

Richter
Цитата(igrik @ 07 Dec 2015, 16:50) *
в z477 - название кнопки, которую хочешь там видеть
Ey3/0/^название основной кнопки^ - оно не изменно, и должно быть прописано у тебя в button.btn.
А ты название новой впилил зачем то в "Ey3/0/^название основной кнопки^"

Например. Старая кнопка называется Butst1, а новая Butst2...
[/code]

Значит для каждого кадра нужна кнопка своя? Видимо я не правильно понял. Думал просто, что контроль за кадрами одного def'а.
Завтра попробую.Сегодня, не дома.Спасибо.
igrik
Вот для одного дефа отображение различных кадров. До конца не разобрался что и как, но работает.
Код
!!FU898112:P25; 25- кадр дефа
!?FU898112;
; x1 - номер кадра  дефа
!!UN:C6918864/4/?y1;
!!VRy1:+84;
!!UN:Cy1/4/?y10;
!!SN:L^Era.dll^/?y2 Ay2/^GetButtonID^/?y3 Ey3/0/^YBackpack^; !!VRy4:Sv1;
!!SN:E6288384/2/y10/512/4/y4/0;
!!SN:E6288528/2/y10/y4/x1;
!!UN:R3/-1;

YBackpack взято из конфига кнопки
Код
Hero;[b]YBackpack[/b];UN44.def;425;430;0;0;Щёлкните здесь, чтобы посмотреть артефакты в рюкзаке героя.;Посмотреть рюкзак;

Если ты знаешь ID кнопки, то можешь без этой лабуды указать ее ID вместо y4 и удалить !!SN:L^Era.dll^/?y2 Ay2/^GetButtonID^/?y3 Ey3/0/^YBackpack^; !!VRy4:Sv1;

upd: На сколько я понял, через данную функцию можно отображать не только дефы, но и текст и *.pcx
Richter
Igrik, можешь подсказать как найти координаты и размер ZGODBON.def. Декомпилят весь излазил уже?
igrik
сомневаюсь, что это есть в декомпелированой базе.
Вскрываешь деф и смотришь, что размер - 44х43
Координаты: если ты спрашиваешь как узнать, то делаешь скрин экрана героя и замеряешь.
Если ты спрашиваешь как изменить эти координаты - то я не знаю как
Richter
Координаты нашел, 127х187 177х187. Только через арт мани терпения не хватает искать. Много значений.
igrik
Второй способ поиска, которым всегда пользуюсь сам, через !!CM:A?y1/?y2; !!IF:M^%Y1 %Y2^;
Richter
Попробовал всё работает. Правда не так немного.
Хотелось бы чтобы работало сразу после триггера !?FU77004;(вход а окно героя). Зашел в экран, а там уже нужный кадр стоит, как навыки героя.
igrik
feanor, а можно создать сразу несколько хуков в одну dll. А то их у меня уже собралось 6 штук. И 6 dll как то некамильфо...
Код
#include
#include
#include "..\..\include\era.h"
#include "..\..\include\patcher_x86_commented.hpp"


Patcher * globalPatcher;
PatcherInstance *patcher;

int __stdcall hook_YAtrCast(LoHook* h, HookContext* c)
{
FireErmEvent(79001);
return EXEC_DEFAULT;
}

int __stdcall hook_YAfterShoot(LoHook* h, HookContext* c)
{
FireErmEvent(79002);
return EXEC_DEFAULT;
}

int __stdcall hook_YAfterStrike(LoHook* h, HookContext* c)
{
FireErmEvent(79003);
return EXEC_DEFAULT;
}



BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        globalPatcher = GetPatcher();
        patcher =  globalPatcher->CreateInstance("igrik_dll");

        ConnectEra();

        patcher->WriteLoHook(0x464FBA, (void*)hook_YAtrCast);
        patcher->WriteLoHook(0x43FF7E, (void*)hook_YAfterShoot);
        patcher->WriteLoHook(0x441AF7, (void*)hook_YAfterStrike);

    }
    return TRUE;
}


upd: хук "hook_YAtrCast" (FireErmEvent(79001)) вызывается дважды, а другие на работают. Млин
feanor
Эм, ну должно работать вроде.
igrik
неа, не работает. Код в точности как я приложил в спойлере

upd: вру:
хук "hook_YAtrCast" (FireErmEvent(79001)) вызывается дважды,
"hook_YAfterShoot" (FireErmEvent(79002)) не вызывается
"hook_YAfterStrike" (FireErmEvent(79003)) вызывается единожды (как и должен)

Видимо где-то я забокопорил, но я в упор не вижу где

* * * * *
upd: ми просто жуткая баклашка, я разобрался.
по первому - у меня уже был плагин с хуком по этому адресу, поэтому дважды
по второму - неправильный адрес хука
по третьему - все было ок
Но это заняло целый час. Господь в одних носках!!!

Все равно мэрси
feanor
Цитата
x3 - кто кастует и описалово как в !!MM: 0 - герой (c вычетом маны и невозможностью каста в этом раунде битвы), 1 - монстр, 2 - арт (зачастую "что попало" в !!MM), 3 - герой (без вычета маны), 4 - герой (без вычета маны + бистро бистро анимация)
Там не совсем что попало, там либо имя артефакта с номером, равным номеру спелла, либо Альянс и Доспехи для соответствующих спеллов (прост где ты видишь в параметрах передаваемый номер арта?)

я в ТоЕ кастовал так

Код
void CastArtifactSpell(int artifact, int spell, int duration)
{
    char* combatManager = (char*)(*((int*)0x699420));
        char *tmp;

        tmp = GetArtifactRecord(spell)->name;
        GetArtifactRecord(spell)->name = GetArtifactRecord(artifact)->name;
        if ( (unsigned char)sub_5A43E0( combatManager, spell, 3, *(int *)(combatManager + 78528), 1, 2) )
          CastBattleSpell(combatManager, spell, -1, 2, -1, 3, duration);
        GetArtifactRecord(spell)->name = tmp;
}


3 и 4, кстати, не предусмотрены конструкцией вроде, так что я очень хз насчет них
igrik
Цитата
Там не совсем что попало, там либо имя артефакта с номером, равным номеру спелла, либо Альянс и Доспехи для соответствующих спеллов (прост где ты видишь в параметрах передаваемый номер арта?)

Да, я не правильно выразился: там имя артефакта с номером спела, и Альянс или Доспехи
Richter
координаты ZGODBON.DEF
ID#139(левая) ;X - 754830h(1b) Y - 75482Bh(4b);
ID#107(правая);X - 7548AAh(1b) Y - 7548A5h(4b);

Менять кадры можно следующим образом;
Для ID#139 Меняем ID на неюзаный, скажем 300 по адресу 754822h,
Далее по средствам ERM ставим нужный кадр по адресу 75481Fh.
для 107, id по адресу 75489Fh, кадр 75489Ch
Обновление Def'a не запилино в функции Dlg_Hero_Update(а жаль), поэтому обновление кадра происходит только после открытия окна героя.
AlexSpl
2feanor:

Вы писали:

Код
PPAdvManager  = ^PAdvManager;
  PAdvManager   = ^TAdvManager;
  TAdvManager   = PACKED RECORD
    Dummy:            ARRAY [0..79] OF BYTE;
    RootDlgIdPtr:     PPINTEGER;
    CurrentDlgIdPtr:  PPINTEGER;
    (* Dummy *)
  END; // .RECORD TAdvManager


  AdvManagerPtr:  PPAdvManager  = Ptr($6992D0);


PROCEDURE GetGameState (OUT GameState: TGameState);
BEGIN
  IF AdvManagerPtr^.RootDlgIdPtr <> NIL THEN BEGIN
    GameState.RootDlgId :=  AdvManagerPtr^.RootDlgIdPtr^^;
  END // .IF
  ELSE BEGIN
    GameState.RootDlgId :=  0;
  END; // .ELSE
  IF AdvManagerPtr^.CurrentDlgIdPtr <> NIL THEN BEGIN
    GameState.CurrentDlgId  :=  AdvManagerPtr^.CurrentDlgIdPtr^^;
  END // .IF
  ELSE BEGIN
    GameState.CurrentDlgId  :=  0;
  END; // .ELSE
END; // .PROCEDURE GetDialogsIds


Похоже, что это то, что нужно, если GameState.RootDlgId - фиксированная и уникальная величина для карты приключений в любой игре. Только есть пара вопросов:
1. ID диалогов в Героях 3 действительно фиксированные величины?
2. Если так, то какой RootDlgId соответствует карте приключений? У меня получилось 6530532. Так ли это?

Получаю так (пока без проверки на nil):

Код
function  GetH3RootDlgID: Integer;
begin
  Result := RPM_INT(RPM_INT(RPM_INT($6992D0) + 80));
end;

RPM_INT - чтение Integer (адрес - аргумент).
feanor
Да, 63A5E4 - фиксированный адрес.
Код
// 63A5E4: using guessed type int (__thiscall *AdvMapDlg_VTable)(void *, char);
AlexSpl
Добавил код для разных версий (вдруг кому пригодится, чтобы не тратить время на поиски адресов). Вписал Вас в Special Thanks (надеюсь, Вы не против).

Код
// Subverions
SV_Complete_RU  = 0;
SV_Complete_EN  = 1;
SV_SoD_EN       = 2;
SV_Chronicles   = 3;
SV_HotA         = 4;      

// Heroes Chronicles
CHAPTER_1       = 0;
CHAPTER_2       = 1;
CHAPTER_3       = 2;
CHAPTER_4       = 3;
CHAPTER_5       = 4;
CHAPTER_6       = 5;
CHAPTER_7       = 6;
CHAPTER_8       = 7;
CHAPTER_UNKNOWN = 8;

...

H3AdvManagerAddr: array[SV_Complete_RU..SV_HotA] of DWORD =
($69CA20, $699280, $6992D0, $000000, $6992D0);

HCAdvManagerAddr: array[CHAPTER_1..CHAPTER_8] of DWORD =
($63B458, $63B450, $63B458, $63D8A0, $63B458, $63D858, $63E8C0, $63E8D0);

H3MapDlgID: array[SV_Complete_RU..SV_HotA] of DWORD =
($63B5F4, $63A5E4, $63A5E4, $000000, $63A5E4);

HCMapDlgID: array[CHAPTER_1..CHAPTER_8] of DWORD =
($5EB594, $5EB594, $5EB594, $5EB594, $5EB594, $5EB594, $5EB5A4, $5EB5A4);

...

function GetH3RootDlgID: DWORD;
var RootDlgIDAddr: DWORD;
begin
  if SubVer <> SV_Chronicles
  then RootDlgIDAddr := RPM_DWORD(RPM_DWORD(H3AdvManagerAddr[SubVer]) + $50)
  else RootDlgIDAddr := RPM_DWORD(RPM_DWORD(HCAdvManagerAddr[HCChapter]) + $50);
  if RootDlgIDAddr <> 0 then Result := RPM_DWORD(RootDlgIDAddr) else Result := 0;
end;

...

function isAdvMapActive: Boolean;
begin
  case Version of
    // Temp Solution
    V_H1: Result := RPM_WORD(GetH1HeroAddr(0) + $3D) <> 0;
    V_H2: Result := RPM_BYTE(GetH2HeroAddr(0) + $63) <> 0;
    // Temp Solution
    else
    if SubVer <> SV_Chronicles then Result := GetH3RootDlgID = H3MapDlgID[SubVer]
      else Result := GetH3RootDlgID = HCMapDlgID[HCChapter];
  end;
end;
AlexSpl
А нет ли случайно в менеджере приключений (advManager) Героев 3 указателя на таблицу виртуальных функций класса icon (const icon::`vftable')? Заметил, что в Героях 1 и 2 этот указатель не равен nil, только если идёт игра на карте приключений.
igrik
feanor, подскажи как это (хоть и работающее) безобразие привести к более презентабельному виду (вложиться в пару строк)
А еще лучше организовать в функцию и показать способ вызова этой функции, которая будет возвращать адрес структуры активного стека. И еще желательно не через __thiscall.
Код
char* combatManager = (char*)(*((int*)0x699420));  // это this_

int j = *(int*)(this_ + 78524);       // номер активного стека текущей стороны 0 ... 20
int i = *(int*)(this_ + 78520);       // номер активной стороны
int v3 = i * 14 + i * 7 + j;          // переход к номеру стека 0 ... 41
int v1 = v3 * 1352;                   // длина структуры одного стека
int v2 = *(int*)(this_ + 21708 + v1); // получить структуру стека
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2025 IPS, Inc.