![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
![]()
Сообщение
#221
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
С замедлением засада вышла...
Была переделана логика замедления. Что бы округлялось в большую сторону. Т.е. 11->6 / 10->5 / 9->5 ... вместо 11->5 / 10->5 / 9->4 ... Проблема следующая, замедление корректно работает только на летающих юнитах. Виверну замедляет с 11 до 6 и пролетает 6 клеток А вот с пешими юнитами пишется скорость (у единорога примеру) 7. После замедления пишется 4. И область хода показывается в 4 клетки. Но по факту проходит 3! Т.е. нажимаю на 4ю клетку, юнит начинает ходить и пройдя 3 клетки останавливается. Или даже лучше. на 4х клетках от врага, пишется что я могу атаковать юнита (появляется меч и пишется (снизу) сколько урона нанесу), нажмая атаковать, юнит проходит 3 клетки и останавливается ![]() Повторюсь, с летающими всё ок Код .text:004489F0; int __thiscall combatMonster_GetSpeed(_CombatMonster_ *this) .text:004489F0 combatMonster_GetSpeed proc near ; CODE XREF: CombatMan_0041E310+F5p .text:004489F0 ; CombatMan_0041E310+109p ... .text:004489F0 .text:004489F0 var_4 = dword ptr -4 .text:004489F0 .text:004489F0 push ebp .text:004489F1 mov ebp, esp .text:004489F3 push ecx .text:004489F4 mov edx, [ecx+270h] .text:004489FA mov eax, [ecx+0C4h] .text:00448A00 test edx, edx ; Logical Compare .text:00448A02 mov [ebp+var_4], eax .text:00448A05 jz short loc_00448A37 ; Jump if Zero (ZF=1) .text:00448A07 mov eax, [ecx+84h] .text:00448A0D shr eax, 6 ; Shift Logical Right .text:00448A10 test al, 1 ; Logical Compare .text:00448A12 jz short loc_00448A1A ; Jump if Zero (ZF=1) .text:00448A14 xor eax, eax ; Logical Exclusive OR .text:00448A16 mov esp, ebp .text:00448A18 pop ebp .text:00448A19 retn ; Return Near from Procedure .text:00448A1A; --------------------------------------------------------------------------- .text:00448A1A .text:00448A1A loc_00448A1A: ; CODE XREF: combatMonster_GetSpeed+22j .text:00448A1A fild [ebp+var_4] ; Load Integer .text:00448A1D fstp [ebp+var_4] ; Store Real and Pop .text:00448A20 fld [ebp+var_4] ; Load Real .text:00448A23 fmul dword ptr [ecx+4C8h] ; Multiply Real .text:00448A29 call __ftol ; Call Procedure .text:00448A2E test eax, eax ; Logical Compare .text:00448A30 jg short loc_00448A37 ; Jump if Greater (ZF=0 & SF=OF) .text:00448A32 mov eax, 1 .text:00448A37 .text:00448A37 loc_00448A37: ; CODE XREF: combatMonster_GetSpeed+15j .text:00448A37 ; combatMonster_GetSpeed+40j .text:00448A37 mov esp, ebp .text:00448A39 pop ebp .text:00448A3A retn ; Return Near from Procedure .text:00448A3A combatMonster_GetSpeed endp используемый код: Код int __stdcall spellSlow(LoHook* h, HookContext* c) { // тут структура монстра лежит в ecx. // откуда мы и можем получить все интересующие нас параметры float speed = (float)(*(int*)(c->ecx +196)); // получаем скорость монстра (структура +196) c->eax = floor( (speed * (*(float*)(c->ecx + 1224))) + 0.5 ); // функция правильного округления (скорость * коэфф.замедления) // а также приходится "обойти" часть оригинального кода c->return_address = 0x448A37; // указываем новый адрес возврата return NO_EXEC_DEFAULT; // после завершения хука не выполняется затертый хуком код } Судя по этому комменту: Цитата в структуре стека в битве есть поле множителя (SlowMul в вогобазе), которое устанавливается при касте скорости и потом используется как коэффициент для актуальной скорости в combatMonster_00448560 (что-то с определением достижимости цели, что ли) и combatMonster_GetSpeed (004489F0, собственно расчет скорости) изменён только метод combatMonster_GetSpeed (хоть и с достижимостью цели проблем не возникло, работает корректно) Попробовал изменить combatMonster_00448560 Код int __stdcall spellSlow2(LoHook* h, HookContext* c) { float speed = (float)(*(int*)(c->ecx +196)); c->eax = floor( (speed * (*(float*)(c->ecx + 1224))) + 0.5 ); c->return_address = 0x4485B5; return NO_EXEC_DEFAULT; } Не помогло... Как сделать корректное замедление для пеших юнитов? PS: Код _PI->WriteLoHook(0x448A1A, spellSlow);
_PI->WriteLoHook(0x4485A5, spellSlow2); |
|
|
![]()
Сообщение
#222
|
|
Immortal Сообщений: 9 444 Спасибо сказали: 3978 раз ![]() |
Функция получения скорости много где подставлена inline. То есть при компиляции кода Героев вместо того, чтобы добавить в некоторые места вызов этой функции, туда была добавлена прямо копия кода этой функции (несколько видоизменённая: с использованием других регистров и т. п.). Для геройского кода это обычное дело, поэтому при модификации не очень больших функций всегда следует исследовать те места, откуда они вызываются, и подумать над тем, не может ли она теоретически использоваться где-то ещё (не забывая, например, про код ИИ).
Часто, впрочем, есть возможность зацеписться за техническую особенность функции и найти её inline-вызовы без понимания, где и зачем они происходят. Здесь тоже повезло: используется редкое смещение +4C8h. Можно просто поиском по ассемблерному тексту найти все использования этого смещения и на взгляд определить, какие именно относятся к получению скорости; соответственно, все их модифицировать. Это не гарантирует того, что будут найдены действительно все inline-вызовы: иногда используется смещённый указатель на структуру, и тогда 4C8h превращается в другое число. Здесь уже помогает только опыт исследования кода и проверка всех мест, откуда потенциально могла бы вызываться эта функций. Но такие случае не так часты. |
|
|
![]()
Сообщение
#223
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
А по каким адресам хуки?
Например, в sub_448560: int speed = *(int*)(c->esi + 196); // скорость float speedMod = *(float*)(c->esi + 1224); // модификатор скорости |
|
|
![]()
Сообщение
#224
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
А по каким адресам хуки? Например, в sub_448560: int speed = *(int*)(c->esi + 196); // скорость float speedMod = *(float*)(c->esi + 1224); // модификатор скорости Я пост выше обновил. Добавил 2 адреса ------------------ По смещению(+4C8h) нашел такую функу. Имеется подозрение что её и надо отредачить: 00441CC0 ; char __thiscall combatMonster_WalkToPos(_CombatMonster_ *a1, signed int a2, char a3) |
|
|
![]()
Сообщение
#225
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
Здесь нужно отследить сам каст "Замедления" и посмотреть, что он делает с модификатором скорости. А иначе придётся перехватывать в коде все умножения скорости на модификатор, и последующее округление (call __ftol).
|
|
|
![]()
Сообщение
#226
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
Вроде сделал!
Код int __stdcall spellSlow3(LoHook* h, HookContext* c) { float speed = (float)(*(int*)(c->esi +196)); c->eax = floor( (speed * (*(float*)(c->esi + 1224))) + 0.5 ); c->return_address = 0x441E36; return NO_EXEC_DEFAULT; } Код _PI->WriteLoHook(0x441E19, spellSlow3);
|
|
|
![]()
Сообщение
#227
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
Лучше управление возвратить по адресу 441E2Dh, а не 441E36h, чтобы выполнилась проверка на 0.
И потом нет гарантии, что учтены все случаи округления. В этом блоке инструкций меняется модификатор при касте Slow: Код .text:00444A33 push 35h
.text:00444A35 mov ecx, esi .text:00444A37 call sub_444230 .text:00444A3C fild [ebp+arg_8] .text:00444A3F fstp [ebp+var_18] .text:00444A42 fld [ebp+var_18] .text:00444A45 fdiv ds:dbl_63A698 .text:00444A4B fstp dword ptr [esi+4C8h] .text:00444A51 fild dword ptr [esi+68h] .text:00444A54 fstp [ebp+var_18] .text:00444A57 fld [ebp+var_18] .text:00444A5A fmul ds:dbl_63B8D8 .text:00444A60 call __ftol .text:00444A65 mov [esi+158h], eax |
|
|
![]()
Сообщение
#228
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
Лучше управление возвратить по адресу 441E2Dh, а не 441E36h, чтобы выполнилась проверка на 0. И потом нет гарантии, что учтены все случаи округления. Переделал, код чуть ниже Насчёт гарантий.. да нету. Но я проверил что смог, как на АИ, так и на ручном управлении юнитами. Как на пеших, так и на летающих. В том числе бонус от родной земли Ещё важный момент, надо было юзать esi, а не ecx во 2й функции Мб кому понадобится: Код .text:00441E19 loc_00441E19: ; CODE XREF: combatMonster_WalkToPos+153j .text:00441E19 fild dword ptr [ebp+a5] ; Load Integer .text:00441E1C fstp dword ptr [ebp+a5] ; Store Real and Pop .text:00441E1F fld dword ptr [ebp+a5] ; Load Real .text:00441E22 fmul dword ptr [esi+4C8h] ; Multiply Real .text:00441E28 call __ftol ; Call Procedure .text:00441E2D test eax, eax ; Logical Compare .text:00441E2F jg short loc_00441E36 ; Jump if Greater (ZF=0 & SF=OF) .text:00441E31 mov eax, 1 Т.е. тут нужное смещение применятся к esi ([esi+4C8h]), а в 1й функе: Код .text:00448A1A loc_00448A1A: ; CODE XREF: combatMonster_GetSpeed+22j .text:00448A1A fild [ebp+var_4] ; Load Integer .text:00448A1D fstp [ebp+var_4] ; Store Real and Pop .text:00448A20 fld dword ptr [ebp-4] ; Load Real .text:00448A23 fmul dword ptr [ecx+4C8h] ; Multiply Real .text:00448A29 call __ftol ; Call Procedure .text:00448A2E test eax, eax ; Logical Compare .text:00448A30 jg short loc_00448A37 ; Jump if Greater (ZF=0 & SF=OF) .text:00448A32 mov eax, 1 Т.е. тут ( [ecx+4C8h]). И юзать надо ecx. Может это и не верный алоритм определения esi/ecs/..., но другого не знаю) Итого, финальный код: Код int __stdcall spellSlow(LoHook* h, HookContext* c) { float speed = (float)(*(int*)(c->ecx +196)); // получаем скорость монстра (структура +196) c->eax = floor( (speed * (*(float*)(c->ecx + 1224))) + 0.5 ); // функция правильного округления (скорость * коэфф.замедления) c->return_address = 0x448A37; // указываем новый адрес возврата return NO_EXEC_DEFAULT; // после завершения хука не выполняется затертый хуком код } int __stdcall spellSlowMelee(LoHook* h, HookContext* c) { float speed = (float)(*(int*)(c->esi +196)); c->eax = floor( (speed * (*(float*)(c->esi + 1224))) + 0.5 ); c->return_address = 0x441E2D; return NO_EXEC_DEFAULT; } Код _PI->WriteLoHook(0x448A1A, spellSlow); _PI->WriteLoHook(0x441E19, spellSlowMelee); |
|
|
![]()
Сообщение
#229
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
Аналогично 0x448A37 на 0x448A2E, иначе пропускается проверка if (speed <= 0) speed = 1;
|
|
|
![]()
Сообщение
#230
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
Аналогично 0x448A37 на 0x448A2E, иначе пропускается проверка if (speed <= 0) speed = 1; заменил, всё работает Терь хочу допилить 2 оставшихся момента с дипломатией... как реализовать возможность сдаваться при бое с монстрами? Т.е. хочу сделать активной кнопку "сдаться" за 30-20-10% от цены войска. Но только при бое с монстрами, против героя не меняя |
|
|
![]()
Сообщение
#231
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
А Haste и Prayer (Молитва) работают нормально?
|
|
|
![]()
Сообщение
#232
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
|
|
|
![]()
Сообщение
#233
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
А куда копать для того что бы реализовать "сдаться" при бое с монстрами?
|
|
|
![]()
Сообщение
#234
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
Это сложная задача, так как алгоритмы написаны для сдачи конкретному герою (его имя в сообщении, и в казну игрока, которому принадлежит этот герой, переводится золото). Для начала я бы нашёл место в коде, где "гасится" кнопка "Surrender".
|
|
|
![]()
Сообщение
#235
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
Посмотрел немного. Если нажать кнопку "Surrender" в бою с нейтралами, игра ведёт себя корректно. Сообщение: "{Hero} surrenders to the enemy, and departs in shame.", герой подает в таверну с войском на момент сдачи. Одно но: нейтралы не требуют денег. Похоже, стоимость сдачи вычитается автоматически.
Наверное, я пропускаю диалог. Так что нужно искать вызов диалога. Диалог - sub_4F6C00. Код по адресу 474919h обрабатывает нажатие кнопки "Surrender", свитч джамп здесь: 474783h (0 - сдаться, 1 - сбежать, 2 - опции и т.д.). Код, который реализует сдачу: 478EBCh, остальные действия в бою: свитч джамп - 47895Fh (функция sub_4786B0). Решение, активна кнопка "Surrender" или нет, принимается здесь: 477EB3h. Примерный алгоритм: 1. Делаем кнопку "Surrender" активной в битве с нейтралами (477EB3h); 2. Реализуем корректный диалог при сдаче нейтралам (474919h); 3. Проверяем код по адресу 478EBCh. Осталось удостовериться, что деньги за откуп уходят в пустоту, а не прописываются по левому адресу. Вылета нет, но проверить стоит. |
|
|
![]()
Сообщение
#236
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
Пробую разрулить с диалогом. Что бы показывался только для героя с дипломатией:
Код int __stdcall setSurrenderButton(LoHook* h, HookContext* c) { char diplomacyLevel = *(char*)(c->esi + 201 + 4); if (diplomacyLevel > 0) { _P = GetPatcher(); _PI = _P->GetInstance("HD.Plugin.DedMorozzz"); _PI->WriteHexPatch(0x477EB3, "9090"); //*(int*)0x477EB3 = 9090; } return EXEC_DEFAULT; } Код _PI->WriteLoHook(0x4AC35E, setSurrenderButton); Не работает. Явно патчер вызывать не надо, но я не знаю как сделать.. В чём была логика - на нужный адрес сделать лоу хук, который проверит наличие вторичного навыка. И если он есть - разблокируем кнопку "сдаться" |
|
|
![]()
Сообщение
#237
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
Можно и через LoHook:
Код int __stdcall setSurrenderButton(LoHook* h, HookContext* c)
{ char diplomacyLevel = *(char*)(*(int*)(c->esi + c->eax * 4 + 0x53CC) + 201 + 4); if ( diplomacyLevel > 0 ) { c->return_address = 0x477EB5; return NO_EXEC_DEFAULT; } return EXEC_DEFAULT; } |
|
|
![]()
Сообщение
#238
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
Можно и через LoHook: Код int __stdcall setSurrenderButton(LoHook* h, HookContext* c) { char diplomacyLevel = *(char*)(*(int*)(c->esi + c->eax * 4 + 0x53CC) + 201 + 4); if ( diplomacyLevel > 0 ) { c->return_address = 0x477EB5; return NO_EXEC_DEFAULT; } return EXEC_DEFAULT; } вылетает. Пробовал 0x477EB5 на 0x477EB3 заменить. То же самое ---------------------- я так понимаю это: char diplomacyLevel = *(char*)(*(int*)(c->esi + c->eax * 4 + 0x53CC) + 201 + 4); не работает. Ибо нападая героем без дипломатии - всё равно вылетает |
|
|
![]()
Сообщение
#239
|
|
Immortal Сообщений: 798 Спасибо сказали: 555 раз ![]() |
Так LoHook на
Код _PI->WriteLoHook(0x477EB3, setSurrenderButton);
|
|
|
![]()
Сообщение
#240
|
|
![]() God Сообщений: 267 Спасибо сказали: 25 раз ![]() |
Так LoHook на Код _PI->WriteLoHook(0x477EB3, setSurrenderButton); да, точно! У меня чего-то вообще на 0x4AC35E стоял. Терь всё ок, не вылетает. Но и кнопки нету)) В смысле не активна PS: её нету даже без условия.. Даже если так написать в ф-ии: Код c->return_address = 0x477EB5;
return NO_EXEC_DEFAULT; |
|
|
![]() ![]() |
Текстовая версия | Сейчас: 3 October 2025 - 23:59 |
Copyright by Алексей Крючков
![]() Programming by Degtyarev Dmitry |
|