Хорошо. Давайте начнем с малого и достаточо простого.
Например, постановка задачи недавно описанная Zur13
(19.07.2020 17:43)Zur13 Wrote: Может ли кто-то подсказать: навык Артиллерия дает 50%,75%,100% шанс баллисте нанести двойной урони дает двойной выстрел. Как это отключить
Итак, разбиваем задачу на 2 этапа:
1. Отключить второй выстрел баллисты при навыке Артилерия
2. Убрать доп.урон с шансами 50%,75%,100%
Я пользуюсь всего двумя:
- IDA Pro + Вогобаза HoMM3 (
ссылка)
- Olly Debager 2.01, например
в первой мне попавшейся ссылке или любой другой вам удобный отладчик.
Внутри "Вогобазы" есть архив с непосредственно самой вогобазой (ваш Кэп), и торрент файл на Ida 7й версии.
Как устанавливать - я не буду объяснять. Думаю, вы и сами справитесь.
Итак, открываем вогобазу через Иду.
1 - список функций, которая нашла Ида в нашем exe. На секундочку - эта вогобаза разобрана по исходнику SOD 3.2. Обязательно имейте это ввиду. Это означает, что воговских функций и адресов вы тут не найдёте! Как их искать я объясню позже
2 - это ASM код. Слева вы можете увидеть как идут адреса в шестнадцетеричной системе ".text:00401000". Как с ними работать для ERM? Сначала нам нужно научиться их переводить в десятеричную систему исчисления (ERM работает только с последней). Итак, открываем калькулятор видновс -> вид -> программист -> нажимаем чекбокс "Hex" -> копируем и вставляем например адрес 00401000 (часто пишут его как 401000h или 0x401000) -> нажимаем на чекбокс "Dec" -> и получаем адрес, представленный в десятеричной системе исчисления, т.е.: 4198400. Т.е. код для UN:C будет иметь вид
!!UN:C4198400/<еще изучим>/<еще изучим>;
3 - обязательно запомните такую кнопку, как
TAB (F5). С помоьщью этой волшебной клавиши, мы можем видеть так называемый С-шный "псевдокод", который намного более читабелен для человека. Ещ` одно нажатие на TAB заставит Иду перейти в ASM код.
Одно замечание на счет ASMа: не поленитесь, изучите что такое команды PUSH, POP, RETN, MOV, CALL, JMP, JNZ, JE. Этого будет хватать на 70% предварительного понимания ASM кода.
Теперь начнем практиковаться.
В ASM коде нажмите клавишу G (или вкладка "Jump->jump to address (7-мая по списку)"), вставте зачение 00475800 в появившееся диалоговое окно, нажмите Ok и сделайте 3-4 скролла средней кнопкой мыши (далее СКМ) вверх.
Мы попали в игровую функцию "Битва: новый раунд". (BattleMgr_NewRound)
Нажимает TAB. Ида декомпелирует и вредоставляет вашему обозрению "превдокод", который выглядит так:
Полистайте скролом и просмотрите этот код. Он более-менее описан уже за вас)
Итог: мы и научились переводить адрес в десятеричную систему из шестнадцетеричной (обратно делается так же, не сложно. Думаю вы и сами догадаетесь.), водить адрес для перехода на участок в exe, и переходить в декомпелированную функцию.
Теперь начнем решать нашу задачу.
Давайте подумаем - а за что нам зацепиться?
Так это баллиста, и вопрос состоял как "отключить второй выстрел", давайте попробуем найти функцию самого выстрела.
Для этого переходим в окно 1 (function name->скролл мышью до конца вверх->клавиша ALT+T->ищем "shoot"->ok)
Ида кидает на с на функцию "AI_Art_ShootingArt_Value". Это не наша. Кликаем в коно №1 (function name) и нажимаем далее "Ctr+T"
"AI_Battle_Defend_Shooter" - опять не наша функция. Опять "Ctr+T"
и так 5-6 раз.
В одном из случаев мы попадаем в функцию "BattleStack__PrepareShoot", т.е. подготовка для выстрела. Для тех, кто не нашел жмем "G" и вводим адрес 43FE80.
Дважды кликаем на неё (функцию BattleStack__PrepareShoot") в окне №1, и после этого в окне №2 откроется псевдокод функции подготовки выстрела. Исследуем его скроллом вниз и находим функцию "BattleStack_Shot". Да, тут Shot написано неправильно, и именно поэтому мы не смогли его найти в поиске раньше. Но вы должны понимать, что вогобаза наполнялась людми, поэтому грамматические ашибки неизбежны. Это именно тот случай. В общем, не важно. Важно что мы добрались до функции выстрела. Детальнее просмотрев код функции подготовки к выстрелу, мы обнаруживаем, что тут целых 3 вызова функции стрельбы.
[spoiler]
Давайте разбираться (0043FF79):
Code:
BattleStack_Shot(stackAtt, target); // первый выстрел стека
if ( ((unsigned int)stackAtt->Flags >> 15) & 1 && target->Count > 0 ) // флаг 15? (2^15=32768 см.ERM хелп флаги монстров: ага, двойная атака. Понятно. "И" цель->количество больше нуля (значит если стек жив))
BattleStack_Shot(stackAtt, target); // делаем второй выстрел.
// смотрим далее
if ( stackAtt->creature_id == 146 && target->Count > 0 ) // ага, катапульта (id=146 и опять если цель жива)
{
v10 = stackAtt->SpellDuration[60]; // ERM help-> заклинания: 60=гипноз
v11 = stackAtt->Side; // проверяем сторону баллисты
v12 = v10 ? 1 - v11 : stackAtt->Side; // тернарный оператор: если под гипнозом, то инвертируем сторону, иначе сторона баллисты
if ( *((_DWORD *)&o_BattleMgr->HeroA + v12) ) // тут мы с помощью определения стороны вычисляем номер героя (см.BA:H)
{
v13 = v10 ? 1 - v11 : stackAtt->Side; // тернарный оператор: но зачем дублировать код? я хз (опять получаем сторону). Возможно обратная перепроверка на стек под гипнозом...
if ( *(_BYTE *)(*((_DWORD *)&o_BattleMgr->HeroA + v13) + 221) > 1 ) (проверяем у героя навык артилерии (герой)+221(201+20_Артилерия) > баз.уровня)
BattleStack_Shot(stackAtt, target); // значит стреляем во второй раз баллистой
}
}
Какие выводы из этой функции?!:
1. Баллиста не имеет флага атаковать дважды. Интересненько, значит можно дать ей этот флаг, и при навыке артиллерии она будет стрелять трижды.
2. Код имеет проверку на "гипноз". WTF? На боевые машины дейстует гипноз? Я хз - нужно проверять. Но в любом случае проверка есть, а это значит,что баллиста под гипнозом по "своим" не будет стрелять во второй раз. Тут уже поле для тестов))
Так как же нам запретить второй выстрел баллисты?
Кликаем мышью (ЛКМ) на цифру 146 в псевдокоде и нажимаем TAB (переходим в ASM код)
Видим, строку
Code:
0043FF9A cmp dword ptr [esi+34h], 92h
где 92h = 146 (id баллисты).
По хорошему, не имея опыта конкеретно тут нужно запускать Olly, в ней запускать игру (желтое поле снизу срава после запуска игры -> эмакаем F9 сколько потребуется раз.) Запускаем карту (обычно тестовую). Переходим в Olly, жмем Ctrl+G, вводим наш адрес 0043FF9A и видим такую картину:
Тут в выделенной строке считаем кол-во байт (начиная с нуля!!)
На третьем счёте видим число 92000000 (это 4 байта!!)
Code:
0043FF9A |> \817E 34 92000000 CMP DWORD PTR DS:[ESI+34],92
Значит, чтобы изменить номер монстра со второым выстрелом под втор.навыком артилерии, можно изменить число по адресу 0043FF9A +3 (4 байта).
Заодно сразу переведем в десятичную систему. Итого
!!UN:C4456349/4/146.
По идее можно изменить число 146 на любое другое.
Так, у нас 196 существ в игре. Значит можно поставить число 250.
Но! Важно помнить, что есть такой прекрасный мод как Тифон!
Но у нас не однобайтовое число, которое может содержать значения от 0...256 (и/или 127/-128).
А плюс в Тифоне существ 0...1000.
Можно запилить существо с id 1001 и дело в шляпе для первого вороса.
Хотя, правильнее вообще вырезать это действие (второй выстрел артилерии).
Но слишком много коньяка, да и рука болит от свеженабитой татухи.
А как это сделать более корректно (вырезать функционал второго выстрела, не меняя id монстра)? Это уже совсем другая история...
Продолжение следует...
PS: Для эксперимента, можно подменить номер баллисты на номер городской башни, и протестировать как они будут вести себя под навыком артилерии.
Бонусов 50%,75%,100% при этом не будет, а будут только у первого выстрела баллисты.