1. Для начала нужно понять где в ИДА искать нужное место, как мы помним из туториала igrik сейчас в ИДА у нас есть только код оригинальных героев без ВоГ, потому начать следует с нахождения исходников BM:P.
После небольшого и безуспешного блуждания по erm.cpp (находится в папке с исходниками ВоГ \Tools\WoG Sources), я понял что команды ЭРМ обрабатываются таким образом:
Code:
switch(Cmd){
case 'T':
Так как подходящей команды в этом файле я не нашел, то воспользовался поиском по содержимому файлов в каталоге исходников ВоГ (\Tools\WoG Sources) с помощью файлового менеджера (Double Commander, или Total Commander), ищем строку "case 'P'" убирая двойные кавычки и оставляя одинарные вокруг Р.
Среди найденых файлов нас интересует Monsters.cpp как самый подходящий по логике. Открыв его текстовым редактором ищем в нем строку "case 'P'" без двойных кавычек.
Первое совпадение нас не интересует так как если прокрутить выше то видим функцию: "int ERM_MonAtr(char Cmd,int Num,_ToDo_*,Mes *Mp)" по названию понятно что это связано с ЕРМ ресивером МА.
А вот второе совпадение это то, что нам нужно потому что чуть выше по коду мы видим интересный коментарий содержащий строчку !!BM:C:
Code:
case 'C': // Cspell/pos/Mskill/HSkill/Check4TargetMonster
if(Num<5){ MError("\"!!BM:C\"-wrong syntax."); RETURN(0) }
Тут мы видим прямо указан ресивер !!BM: значит мы нашли функцию где он обрабатывается, а вот это место в ней это как раз то что мы искали:
Code:
case 'P':
if(Mp->VarI[0].Check==1){ // ?
Apply((int *)&mon[0x038],4,Mp,0);
}else{
Apply(&val,4,Mp,0);
val2=*(int *)&mon[0x0C4]; // запомним скорость
*(int *)&mon[0x0C4]=999; // установим гигантскую скорость
val3=*(Dword *)&mon[0x084]; // запомним флаги
*(Dword *)&mon[0x084]|=2; // установим летучесть
__asm{
mov eax,0x4F8980
mov byte ptr [eax],0xC3
// mov eax,0x4468E7
// mov dword ptr [eax],0x000001B9
// mov word ptr [eax+4],0x9000
mov eax,val
mov ecx,mon
push 1
push eax
mov eax,0x445A30
call eax
mov eax,0x4F8980
mov byte ptr [eax],0x55
// mov eax,0x4468E7
// mov dword ptr [eax],0x89E80D8B
// mov word ptr [eax+4],0x0069
}
*(Dword *)&mon[0x084]=val3; // восстановим флаги
*(int *)&mon[0x0C4]=val2; // восстановим скорость
}
В этом блоке, ближе к концу мы видим
Code:
mov eax,0x445A30
call eax
что является вызовом какой-то функции по адресу 445A30, копируем этот адрес и идем в ИДА.
2. В ИДА делаем переход по адресу нажимаем G и в появившемся окне вводим наш адрес 445A30 дважды жмем Ентер и перехоим в режим псевдокода С (нажатием клавиши Tab). Там мы видим следующее:
Code:
char __thiscall BattleMgr_MoveMonstre(_BattleStack_ *this, int gex, char zero)
{
return Battle_Stack_MoveToPosition(this, gex, zero);
}
>>> Tutorial 1.jpg
Мы видим что по искомому адресу располагается функция которая в свою очередь просто вызывает другую функцию с именем "Battle_Stack_MoveToPosition" очень похоже что мы нашли именно то что мы искали.
Теперь мы знаем что BM:P вызывает функцию Battle_Stack_MoveToPosition чтобы переместить стек на поле битвы в нужную позицию. Двойной клик по имени функции в окне открывает её в этом же окне, нажатие клавиши ESC возвращает туда откуда мы перешли в эту функцию.
Далее я пропускаю ту часть где я 4 часа лазил по этому коду пытаясь определить и пропатчить места где он мог предположительно падать, пока наконец не додумался посмотреть в крешлог...