Wake of Gods Forum | Форум Во Имя Богов

Full Version: Исследование героев
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Функция, рассчитывающая бонус к урону для башни.

Code:
double __thiscall A0_Battle_Stack_Get_ArrowTower_DamageBonus_To_sub_443AB0(struct_BattleStack *this, char IsShot)
{
  double Shild_Spells_Mult_v2; // st7@3
  int Controller_v3; // eax@10
  int Hero_v4; // eax@12
  double Base_mult_v6; // [sp+0h] [bp-8h]@1

  *(_QWORD *)&Base_mult_v6 = 0x3FF0000000000000ui64;// double 1.0
  if ( IsShot )
  {
    if ( !this->Spells_Lengths_adword198[28] )  // Воздушный щит
      goto CHECK_STONE_SPELL_L7;
    Shild_Spells_Mult_v2 = this->AirShieldSpell_Modif_dword4BC;
  }
  else
  {
    if ( !this->Spells_Lengths_adword198[27] )  // Щит
      goto CHECK_STONE_SPELL_L7;
    Shild_Spells_Mult_v2 = this->ShieldSpell_Modif_dword4B8;
  }
  Base_mult_v6 = Shild_Spells_Mult_v2;
CHECK_STONE_SPELL_L7:
  if ( this->Spells_Lengths_adword198[70] )     // Окаменение
    Base_mult_v6 = Base_mult_v6 * 0.5;
  if ( this->Spells_Lengths_adword198[60] )     // Гипноз
    Controller_v3 = 1 - this->Owner_dwordF4;
  else
    Controller_v3 = this->Owner_dwordF4;
  Hero_v4 = *(_DWORD *)(A0_BattleMgr_dword_699420 + 4 * Controller_v3 + 21452);
  if ( Hero_v4 )
    Base_mult_v6 = A0_Hero_GetDefense_SecSkill_sub_4E4580(Hero_v4) * Base_mult_v6;
  return Base_mult_v6;
}

Забавно, что получаемый бонус явно рассчитан на то, чтобы на него урон умножали, но урон на него во всех случаях использования этой функции делится. Отсюда и баг с воздушным щитом, окаменением и (не помню, известен ли он) вторичным навыком Защиты.

Так же несложно заметить, что в функции рассчитывается всего 3 вещи - воздушный щит (IsShot во всех стандартных вызовах = 1), окаменение и вторичный навык Защита (со специализацией) героя-хозяина цели. Ни атака (а ведь у башни заявлено 10 атаки) с защитой, ни вторичные навыки героя-хозяина башни не учитываются.

Для Хоты я заменил все 3 вызова этой функции на нормальную A0_Battle_Stack_CalcDamageModifs_sub_443C60 (пришлось искать недостающие параметры, но это несложно). Это и исправит баги, и несколько усилит башни (учитывающиеся 10 атаки - не так мало + учёт атаки обороняющегося героя).
Хотелось бы в Эру по умолчанию встроить. Двоичной заплаткой не обойтись?
Могу дать код, но он основан на Patcher_x86. Там несколько хуков.
Да, и он на C++.
Давай.
(20.03.2012 23:18)Sav Wrote: [ -> ]Функция, рассчитывающая бонус к урону для башни.

Code:
double __thiscall A0_Battle_Stack_Get_ArrowTower_DamageBonus_To_sub_443AB0(struct_BattleStack *this, char IsShot)
{
  double Shild_Spells_Mult_v2; // st7@3
  int Controller_v3; // eax@10
  int Hero_v4; // eax@12
  double Base_mult_v6; // [sp+0h] [bp-8h]@1

  *(_QWORD *)&Base_mult_v6 = 0x3FF0000000000000ui64;// double 1.0
...

А там точно double, а не float? Раньше думал, что в игре используется только float32.
Code:
// При подсчёте бонуса к урону стрелковой башни...
int __stdcall HookOn_ArrowTowerCalcDamageBonuses(LoHook* h, HookContext* c)
{
  // Вызываем общую функцию подсчёта урона.
  c->eax = (*(_BattleStack_**)(c->ebp - 36))->Calc_Damage_Bonuses((_BattleStack_*)(c->ebx), *(_int32_*)(c->ebp + 8), TRUE, FALSE, 0, 0);
  
  c->return_address = 0x46594B;
  
  return NO_EXEC_DEFAULT;
}



// При подсчёте бонуса к урону стрелковой башни ИИ (1)...
int __stdcall HookOn_ArrowTowerCalcDamageBonusesAI1(LoHook* h, HookContext* c)
{
  // Выполняем затёртую команду.
  c->edi = c->esi - 688;
  
  // Вызываем общую функцию подсчёта урона.
  c->eax = ((*(_BattleMgr_**)(c->ebp - 16))->stack[(*(_BattleMgr_**)(c->ebp - 16))->current_side][(*(_BattleMgr_**)(c->ebp - 16))->current_stack_ix]).Calc_Damage_Bonuses((_BattleStack_*)(c->edi), *(_int32_*)(c->ebp + 16), TRUE, TRUE, 0, 0);
  
  c->return_address = 0x41E3AB;
  
  return NO_EXEC_DEFAULT;
}


// При подсчёте бонуса к урону стрелковой башни ИИ (2)...
int __stdcall HookOn_ArrowTowerCalcDamageBonusesAI2(LoHook* h, HookContext* c)
{
  // Выполняем затёртую команду.
  c->edi = c->esi - 688;
  
  // Вызываем общую функцию подсчёта урона.
  c->eax = ((*(_BattleMgr_**)(c->ebp - 16))->stack[(*(_BattleMgr_**)(c->ebp - 16))->current_side][(*(_BattleMgr_**)(c->ebp - 16))->current_stack_ix]).Calc_Damage_Bonuses((_BattleStack_*)(c->edi), *(_int32_*)(c->ebp + 16), TRUE, TRUE, 0, 0);
  
  c->return_address = 0x41E4E7;
  
  return NO_EXEC_DEFAULT;
}
Code:
Patcher* _P = GetPatcher();
PatcherInstance* _PI = _P->CreateInstance("Choose_Name");
Code:
// При подсчёте бонуса к урону стрелковой башни...
_PI->WriteLoHook(0x465934, HookOn_ArrowTowerCalcDamageBonuses);

// При подсчёте бонуса к урону стрелковой башни ИИ (1)...
_PI->WriteLoHook(0x41E38E, HookOn_ArrowTowerCalcDamageBonusesAI1);

// При подсчёте бонуса к урону стрелковой башни ИИ (2)...
_PI->WriteLoHook(0x41E4CA, HookOn_ArrowTowerCalcDamageBonusesAI2);

Не хочу менять сам код (наделаю синтаксических ошибок ещё), поэтому поясню отдельно: _int32_ = int; TRUE = 1; FALSE = 0.
Code:
struct _BattleStack_
{
...
    // Подсчёт добавок к наносимому урону (возвращается новый урон).
    // Enemy - указатель на атакуемый стек.
    // BaseDamage - начальный урон.
    // IsShot - является ли атака выстрелом (TRUE - является).
    // Virtual - является ли подсчёт производимым ИИ (TRUE - является).
    // WayLength - пройденный путь до цели (для расчёта кавалерийского бонуса).
    // out_FireshieldDamage - указатель на переменную, в которую в результате работы функции запишется урон от огненного щита (0 - не подсчитывать).
    inline _int32_ Calc_Damage_Bonuses(_BattleStack_* Enemy, _int32_ BaseDamage, _bool8_ IsShot, _bool8_ Virtual, _int32_ WayLength, _int32_* out_FireshieldDamage)
    {
      return CALL_7(_int32_, __thiscall, 0x443C60, this, Enemy, BaseDamage, IsShot, Virtual, WayLength, out_FireshieldDamage);
    }
...
}
_BattleMgr_.stack = +21708, массив 2 на 21 стеков (каждый - по 1352 байта).
_BattleMgr_.curr_stack_ix = +78524
_BattleMgr_.current_side = +78528


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

etoprostoya Wrote:А там точно double, а не float? Раньше думал, что в игре используется только float32.
64 тоже используется, в основном в промежуточных вычислениях. Хотя конкретно в этом случае не знаю, но, думаю, Ида правильно определила, тем более в такой маленькой функции.
Понятно. Ида просто не может отличить код для double от кода для float, если это не SSEx. Код для 64- и 32- битных плавающих числе отличается только в инициализации.
Подскажет кто-нибудь, почему триггер в данной функции срабатывает только со второй генерации случайной карты?

Врезка идет сразу после нажатия кнопки "начать" перед генерацией карты по адресу 0x5863ba.
Если то же самое сделать с помощью функции Эры ExecErmCmd, то срабатывает нормально - при первой же генерации.

В данном случае нужно получить значение одной из ВОГ-опций.
Это можно попробовать сделать и без ЕРМ, но возни много.
И, самое главное, что дальше после генерации карты нужно будет организовать интерфейс с помощью ВОГ-диалога, там уже по любому ЕРМ нужен.

Зависимость от Эры не устраивает, т.к. скорее всего программа будет использоваться в ТЕ/WT.
кто-нибудь знает как получить указатель на массив героев?
Разная инфа хранится в разных массивах. Основной: *(_ptr_*)0x699538 + 0x21620 (размер элемента: 1170 байт).
В начале 2^32 - 1 раунда все непризванные стеки на поле боя погибнут (призванные сделают это в начале 2^32 - 1 раунда, считая с момента призыва). Это связано с полем, отвечающим за оставшиеся раунды жизни клонов, которое при инициализации -1, для клона отдельно устанавливается, и при уменьшении которого нет никаких проверок.
(28.03.2012 16:37)Sav Wrote: [ -> ]В начале 2^32 - 1 раунда все непризванные стеки на поле боя погибнут
От черт.... значит нельзя бесконечно смотреть на 2х дерущихся троллей 118
Я кстати на df2 упоминал о подобном "переполнении" при споре, можно ли гарпией ведьмой при определенном сочетании препятствий на поле боя завалить 100500 бегемотов. Хотя, за миллиард ходов конкретно 100500 бегемотов лягут...
Ну, бегемоты-то всё равно умрут в результате. Sm
(28.03.2012 18:20)Algor Wrote: [ -> ]От черт.... значит нельзя бесконечно смотреть на 2х дерущихся троллей 118
даже если раунд будет занимать 1 секунду, тебе хватит раундов для непрерывного просмотра в течении 136 лет Sm
Возможно, быстрая битва не предусматривает другого выхода из подобных ситуаций.
Reference URL's