Current time: 13.04.2024, 13:13 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
Решение багов ERA/WOG
» Примеры решения багов ERA/WOG на уровне кода.
Author Message
igrik Offline
Administrators

Posts: 2813
Post: #1
Баг 
Данная тема предназначена только для выкладывания кода лечения багов (непосредственно касающихся Вога или Эры) на программном уровне, для того чтобы Berserker мог их включать в состав era.dll
Любые сообщения, не содержащие указание бага совместно с его решением на Ассамблере, Delphi или С++ будут безжалостно уничтожаться.


Я буду данные фиксы включать в плагин game bug fixes extended.dll
Исходник можно увидеть тут: github.com
Список фиксов (Click to View)


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

Posts: 2180
Post: #2

Я всё-таки разобрался со шрифтами.
Вот патч:
PHP Code:
// Исправляем обработку отрицательного отступа шрифта (ошибку приведения типов).
_PI->WriteByte(0x4B5349 10xB6); // (mov)zx
_PI->WriteByte(0x4B53E5 10xB6); // (mov)zx 

Ошибка эта была не в алгоритме, а в приведении типов, поэтому её не видно в выложенном мной декомпилированном коде.

Вот код, содержащий ошибку:
Code:
.text:004B5335 ; 109:             if ( *((_DWORD *)&this_v11->v_table + 3 * (symbol_v21 + 5)) < 0 )// fnt->char_sizes[symbol].width
.text:004B5335                 mov     edx, eax
.text:004B5337                 and     edx, 0FFh
.text:004B533D                 add     edx, 5
.text:004B5340                 lea     edx, [edx+edx*2]
.text:004B5343                 cmp     dword ptr [ebx+edx*4], 0
.text:004B5347
.text:004B5347 loc_4B5347:                             ; DATA XREF: 0138630Ao
.text:004B5347                 jge     short loc_4B5357
.text:004B5349 ; 110:               symbols_width_v19 = -*((_DWORD *)&this_v11->v_table + 3 * ((char)symbol_v21 + 5));// fnt->char_sizes[symbol].width
.text:004B5349                 movsx   ecx, al
.text:004B534C
.text:004B534C loc_4B534C:                             ; DATA XREF: 018ECE8Co
.text:004B534C                 add     ecx, 5
.text:004B534F                 lea     ecx, [ecx+ecx*2]
.text:004B5352                 mov     ecx, [ebx+ecx*4]
.text:004B5355                 neg     ecx
Тут левый отступ первого символа строки сравнивается с 0, а потом, если он отрицательный, ecx устанавливается в -него (чтобы потом, когда он в цикле прибавится, скомпенсировать его, чтобы таким образом игнорировать отрицательный отступ первого символа строки).
Проблема в строке ".text:004B5349 movsx ecx, al". Ведь если символ русский, al будет отрицательной и в ecx запишется отрицательное число, которое потом будет использоваться как индекс. В результате, вместо отступа будет взят мусор (например, 0xBAADF00D), из-за которого строка уползёт чёрт знает куда. Ну или там может лежать 0 и недочёт не будет заметен.
Такая же вещь с правым отступом последнего символа строки.

Патч правит movsx на movzx, в результате чего знак игнорируется и для русских букв генерируются нормальные индексы.
(This post was last modified: 06.07.2012 20:52 by Sav.)
06.07.2012 18:55
Find all posts by this user Quote this message in a reply
Sav Offline

Posts: 2180
Post: #3

Исправление одного из вылетов при загрузке карты / наступлении новой недели.
PHP Code:
_PI->WriteDword(0x4CCC43IntAt(0x4CCC43) - 4); 

Этот вылет связан с содовским багом (возможно, только 3.2) генерации слуха в таверне. Там берётся случайное число от 1 до 256 и по нему как по индексу берётся значение (адрес строки слуха) из 256-элементного массива. Соответственно, первый слух никогда не берётся, зато иногда берётся элемент "за последним", он равен 0, и происходит вылет.
Раньше мне казалось, что в Воге что-то намутили с таблицей слухов и там этого вылета нет, но теперь я поймал его в Эре.

Этот баг фактически обеспечивал 0.4% шанса вылететь каждую неделю. Sm
(This post was last modified: 11.07.2012 20:37 by Sav.)
11.07.2012 20:36
Find all posts by this user Quote this message in a reply
MOP Offline
Moderators

Posts: 1468
Post: #4

Исправление бага отображения русских букв в диалоге опыта существ (некоторые способности - чёрточки вместо слов):

Code:
722792 B6


Circle of destruction, hammer comes crushing
Powerhouse of energy
Whipping up a fury, dominating flurry
We create the battery
(This post was last modified: 20.09.2012 21:31 by MOP.)
20.09.2012 21:27
Find all posts by this user Quote this message in a reply
MOP Offline
Moderators

Posts: 1468
Post: #5

деактивация вог-проверок, вызывающих потерю опыта последнего отряда (exe-адреса):

Code:
2F3C55 EB0C
2F3BEC EB0C
2F42E6 EB0C
2F4356 EB0C

Исходники WoG, Monsters.cpp - поиск по фразе "хочет перенести последний стэк - не получится". Sm


Circle of destruction, hammer comes crushing
Powerhouse of energy
Whipping up a fury, dominating flurry
We create the battery
(This post was last modified: 28.09.2012 07:27 by MOP.)
28.09.2012 07:27
Find all posts by this user Quote this message in a reply
Sav Offline

Posts: 2180
Post: #6

Некоторое время назад я исправлял вылеты, связанные со слухами в таверне. Сейчас я подробно исследовал тот код и понял, что прошлый мой фикс был не совсем правильным: вылет-то он исправлял, но не исправлял нарушенный механизм генерации слухов, делающий некоторые из них недоступными, а некоторые генерирующимися слишком часто, особенно через большое количество недель после начала игры.
Вместо
Code:
_PI->WriteDword(0x4CCC43, 0x696DE8);
Следует вставить
PHP Code:
_PI->WriteHexPatch(0x4CCC40 2"8D"); // mov ..., ...[ecx*4] 
14.04.2013 20:33
Find all posts by this user Quote this message in a reply
gamecreator Offline

Posts: 7107
Post: #7

(07.04.2015 00:51)Elzivir Wrote:  при нападении героя AI на человека в режиме одиночной игры и при попытке последнего путем нажатия ПКМ на кнопку Defend (оборона) поменять тип атаки лучников/командира со стрельбы на рукопашную, выдается сообщение: "This feature does not work in Human vs Human network baced battle", т.е. если стрелки никем не заблокированы им остается лишь дистанционная атака, а переход в режим рукопашного боя невозможен, даже если вражеский юнит находится в пределах досягаемости. Причем, если на стороне атакующего героя будет человек, то данной проблемы не возникает

(07.04.2015 01:16)Berserker Wrote:  Может быть кто-нибудь напишет патч, отключающий проверку.

Лучше. Меняем проверку флага 997 на 998 (патч для памяти):
Code:
762604 С5


When all gods have burnt to ashes in eternity of sorrow,
Demons gonna tear your soul because there is no tomorrow.
07.04.2015 02:19
Find all posts by this user Quote this message in a reply
gamecreator Offline

Posts: 7107
Post: #8

Ok, I found the problem. There is a fatal flaw in the hint system, making so that no hint can be set twice. I can imagine how ZVS / sergroj / whoever else made WoG T1 managed to compile this incorrect code. A good example of why one shouldn't use outdated compilers they don't understand.
Anyhow, here is the fix (hopefully without errors, because I didn't test it):
Code:
72982C FC
729835 FC
72983B FC
729843 FC
729859 FC
72987B FC
72988F FC


When all gods have burnt to ashes in eternity of sorrow,
Demons gonna tear your soul because there is no tomorrow.
31.05.2016 02:48
Find all posts by this user Quote this message in a reply
igrik Offline
Administrators

Posts: 2813
Post: #9

Решение бага Вога, когда в бою накладывается опыт через EA:E и атака, защита, уроны, скорость, боезапасы и т.п. заново пересчитываются.
Из-за этого теряются бонусы наложенных заклинаний (например бонус скорости от ускорения)

Сама функция пересчета параметров стека из исходников WoG:
0x726DE4 тут вызывается функция установки опыта в бою (и этот баг) через EA:E = CrExpBon::Apply(MonPos(Type)); (стр.4886)
int CrExpBon::Apply(Byte *Mon){ // настройка бонусов на поле боя один раз (стр 1495 crexpo.cpp)

Code:
int __stdcall ERM_Fix_EA_E(HiHook* hook, _BattleStack_* stack )
{
    int ret = 0;
    _int32_ spell_duration[81]; // для сохранения длительности заклинаний
    _int32_ spells_power[81];   // для сохранения силы действия заклинания

    if (stack) {
        for (int i=0; i<80; i++) {
            spell_duration[i] = stack->active_spell_duration[i];
            spells_power[i] = stack->active_spells_power[i];

            if (spell_duration[i] > 0 ) // если заклинание наложено на стек, то сбрасываем его эффект
                CALL_2(int, __thiscall, 0x444230, stack, i); // ResetSpellFromStack 0x444230
        }
    }

    ret = CALL_1(int, __cdecl, hook->GetDefaultFunc(), stack);

    for (int i=0; i<80; i++) {
        if (spell_duration[i] > 0) { // если заклинание ранее было наложено, то восстанавливаем его
            CALL_5(int, __thiscall, 0x444610, stack, i, spell_duration[i], spells_power[i], 0); // ApplySpell 0x444610
        }
    }

    return ret;
}
/////////////////////////////////////////////////////////////
_PI->WriteHiHook(0x726DE4, CALL_, EXTENDED_, CDECL_, ERM_Fix_EA_E);
01.02.2019 15:40
Visit this user's website Find all posts by this user Quote this message in a reply
igrik Offline
Administrators

Posts: 2813
Post: #10

Решение багов ИИ, когда тот может (© RoseKavalier):
1. Использовать заклинание полёт когда у него нет Крыльев Ангела или Полёта
2. Использовать заклинания на Проклятой Земле, которые на ней запрещены
Code:
int __stdcall AI_waterwalk_fly(LoHook *h, HookContext *c)
{
    if (c->eax == 0) // no angel wings
    {
        _Hero_ *hero = (_Hero_ *)(c->esi);
        if (hero->spell[6] == 0 && hero->spell_level[6] == 0) // this AI hero does not have the means to cast fly (id = 6)
        {
            if (hero->spell[7] != 0 || hero->spell_level[7] != 0) // this AI hero has access to waterwalk (id = 7)
            {
                if (hero->waterwalk_cast == -1) // waterwalk is not cast ~ waterwalk field is *(&hero + 0x116) (see 0x4E6040 Cast_waterwalk function)
                    c->return_address = 0x430231; // try to cast waterwalk instead (code checks for Boots of Levitation first...)
                else
                    c->return_address = 0x430540; // skip procedure
                return NO_EXEC_DEFAULT;
            }
        }
    }
    return EXEC_DEFAULT;
}

int __stdcall AI_TP_cursed_check(LoHook *h, HookContext *c)
{
    _Hero_ *hero = (_Hero_*)c->esi;
    if (hero->GetSpecialTerrain() == 0x15) // 0x15 = cursed ground, 0x4E5130: __thiscall GetSpecialTerrain()
    {
        c->return_address = 0x56B6F4;
        return NO_EXEC_DEFAULT;
    }
    return EXEC_DEFAULT;
}

_PI->WriteLoHook(0x56B344, AI_TP_cursed_check);
_PI->WriteLoHook(0x43020E, AI_waterwalk_fly);


Решение бага (еще с SoD) исчезновения улучшенного стека при битве с даунгрейдом нейтралов
Code:
_int_ __stdcall Y_FixBagCreatureGredeOfNeutrals(HiHook* hook, _Army_* army, _int_ creature_id)
{
    _int_ count = 0;
    _int_ i = 0;
    _int_ crGrade_id = GetCreatureGrade(creature_id);
    do {
        if (army->type[i] == creature_id || army->type[i] == crGrade_id) {
            count += army->count[i];
        }
        i++;
    } while ( i<7 );

    return count;
}

//////////////////////////////////////////////////////////////

_PI->WriteHiHook(0x4AC5F5, CALL_, EXTENDED_, THISCALL_, Y_FixBagCreatureGredeOfNeutrals);


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

Posts: 2813
Post: #11

Исправление бага с исчезновением стартового героя при переигрывании
Code:
_PI->WriteByte(0x5029C0, 0xEB);

Исправление бага палатки, когда на её ходу невозможно убежать или сделать другие действия
Code:
_PI->WriteByte(0x75C82C, 0xEB);

Исправление недочета WoGа на расширение свитча хинтов колдовства для описаний командиров и монстров с номером больше 134
Code:
_PI->WriteHexPatch(0x492A56, "81FF B7000000 90 7747");
_PI->WriteDword(0x492A63, *(_int_*)0x44825F);

Исправление одного из багов Астрального духа
Т.е. убираем WoG сообщение, которое вызывает неизвестную ошибку в малочисленном ряде случаев
Code:
_PI->WriteHexPatch(0x76D4B3, "EB17");

Исправление бага блока командира, когда защита падала из-за флага "в защите"
Code:
_PI->WriteCodePatch(0x76E7D7, "%n", 24); // 15 nop
_PI->WriteCodePatch(0x76E80B, "%n", 13); // 13 nop
_PI->WriteHexPatch(0x76E7D7, "8B4D 08 C601 01 C641 02 04");

Исправление ошибки ERM (видимо опечатки Славы ZVS) в командре IF:N1.
Теперь команда работает со всеми локальными, глобальными и отрицательными переменными z, а не только с z1
Code:
_PI->WriteByte(0x749093, 0xB0);
_PI->WriteByte(0x74909C, 0xB0);
_PI->WriteByte(0x7490B0, 0xB0);
_PI->WriteByte(0x7490B6, 0xB0);
_PI->WriteByte(0x7490CD, 0xB0);

Меняем месторасположение кнопки Сказочного Дракона
Code:
// исправить координаты кнопки
_PI->WriteDword(0x5F3D9F, 235); // подложка поз.Y
_PI->WriteByte(0x5F3DA4, 21);    // подложка поз.X
_PI->WriteDword(0x5F3DF5, 235); // кнопка   поз.Y
_PI->WriteByte(0x5F3DFA, 21);    // кнопка   поз.X


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

Posts: 2813
Post: #12

Убираем показ (предварительного расчета в строке состояния битвы) увеличенного урона от кавалерийского бонуса, если существо летает.
Потому что в оригинале бонус кавалерии не действует (при нанесении фактического урона) у летающих существ.
Code:
// не считать кавалерийский бонус при полете
_int_ __stdcall Y_AntiKavalierAndFly(LoHook* h, HookContext* c)
{
    if ( *(_dword_*)(c->ebx +132) >> 1 & 1 ) { // проверить флаг атакующего на полет
        c->return_address = 0x4430A3; // обходим расчет кавалерийского бонуса (он всё равно не работает)
        return NO_EXEC_DEFAULT;
    }
    return EXEC_DEFAULT;
}
///////////////////////////////////////////////

_PI->WriteLoHook(0x44307A, Y_AntiKavalierAndFly); // не считать кавалерийский бонус при полете


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

Posts: 2813
Post: #13

Решение бага ERM: триггер MA:U#/-2 приводил к тому, что любое существо при установке такой команды улучшалось в копейщика. Подробнее тут
Плагин: скачать

Code:
int __stdcall Fix_WoG_GetCreatureGrade_Expo(LoHook* h, HookContext* c)
{
    if ( *(int*)(c->ebp -4) < -1) {
        *(int*)(c->ebp -4) = -1;
    }
    return EXEC_DEFAULT;
}

int __stdcall Fix_WoG_GetCreatureGrade_Town(LoHook* h, HookContext* c)
{
    if (*(int*)0x27F93B0 < -1) { // FOH_ret < -1
        *(int*)0x27F93B0 = -1;
    }
    return EXEC_DEFAULT;
}
///////////////////////////////////////////////
_PI->WriteDword(0x724A9F, -2);    
_PI->WriteLoHook(0x724AC5, Fix_WoG_GetCreatureGrade_Expo);

_PI->WriteDword(0x74ED27, -2);  
_PI->WriteLoHook(0x74ED5C, Fix_WoG_GetCreatureGrade_Town);


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

Posts: 2813
Post: #14

Решение нескольких крит.вылетов в игре в режиме битвы
Code:
// фикс вылета: АИ битва (просчёт)
// проверка на скорость монстра и когда он дойдет до защиты стрелка.
// Убираем из проверки существ с нулевой скоростью и боевые машины
_int_ __stdcall Y_AIMgr_Stack_MinRoundToReachHex(HiHook* hook, _dword_ this_, _BattleStack_* stack, _int_ a3)
{
    if (stack->creature.flags == BCF_CANT_MOVE || stack->creature.speed < 1)
        return 99; // 99 раундов необходимо, чтобы добраться до стрелка

    return CALL_3(_int_, __thiscall, hook->GetDefaultFunc(), this_, stack, a3);
}

_PI->WriteHiHook(0x4B3C80, SPLICE_, EXTENDED_, THISCALL_, Y_AIMgr_Stack_MinRoundToReachHex);

Code:
// фикс вылета: нет проверки на наличие стуктуры целевого стека при воскрешении
// тут не хватает проверки на c->edi
int __stdcall Y_FixCrash_CastSpell_38(LoHook* h, HookContext* c)
{
    if ( c->edi )
    {
       c->eax = *(int*)(c->edi + 0x38);
       c->ecx = *(int*)(c->ebx + 0x132C0);
       c->return_address = 0x5A1C20;
      
    }  else c->return_address = 0x5A2368;

    return NO_EXEC_DEFAULT;
}

_PI->WriteLoHook(0x5A1C17, Y_FixCrash_CastSpell_38);

Code:
// фикс вылета: при удалении препятствия в битве нет проверки на наличие стуктуры его дефа
// (привет WoG и его стена огня у Огненных Лошадей)
int __stdcall Y_FixCrash_RemoveObstackle(LoHook* h, HookContext* c)
{
    // проверяем на пустую структуру боевого пропятствия
    // чтобы пропустить код обращения к ней и как следствие крит.краш.игры
    if ( !c->ecx || !c->edi )
    {
       c->return_address = 0x466826;
       return NO_EXEC_DEFAULT;  
    }

    return EXEC_DEFAULT;
}

_PI->WriteLoHook(0x46681B, Y_FixCrash_RemoveObstackle);
11.10.2020 19:37
Visit this user's website Find all posts by this user Quote this message in a reply
slater777 Offline

Posts: 136
Post: #15

Фикс бага WOG'a

Code:
_LHF_(HooksInit)
{
    // Фикс Димера - герой имеет продвинутую разведку на старте
    h3::H3HeroInfo* hero_info_table = P_HeroInfo->Get();
    hero_info_table[eHero::DEEMER].sskills[1].level = eSecSkillLevel::BASIC;
}

_PI->WriteLoHook(0x4EEAF2, HooksInit);
(This post was last modified: 08.01.2023 09:56 by slater777.)
08.01.2023 06:37
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