Current time: 18.04.2024, 18:11 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
Исследование героев
» туториал(ы)
Author Message
Sav Offline

Posts: 2180
Post: #451

Функция, рассчитывающая бонус к урону для башни.

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 атаки - не так мало + учёт атаки обороняющегося героя).
(This post was last modified: 20.03.2012 23:19 by Sav.)
20.03.2012 23:18
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16477
Post: #452

Хотелось бы в Эру по умолчанию встроить. Двоичной заплаткой не обойтись?


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
20.03.2012 23:26
Find all posts by this user Quote this message in a reply
Sav Offline

Posts: 2180
Post: #453

Могу дать код, но он основан на Patcher_x86. Там несколько хуков.
Да, и он на C++.
(This post was last modified: 20.03.2012 23:29 by Sav.)
20.03.2012 23:28
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16477
Post: #454

Давай.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
20.03.2012 23:59
Find all posts by this user Quote this message in a reply
etoprostoya Offline

Posts: 1809
Post: #455

(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.
21.03.2012 00:36
Find all posts by this user Quote this message in a reply
Sav Offline

Posts: 2180
Post: #456

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 тоже используется, в основном в промежуточных вычислениях. Хотя конкретно в этом случае не знаю, но, думаю, Ида правильно определила, тем более в такой маленькой функции.
(This post was last modified: 21.03.2012 00:56 by Sav.)
21.03.2012 00:52
Find all posts by this user Quote this message in a reply
etoprostoya Offline

Posts: 1809
Post: #457

Понятно. Ида просто не может отличить код для double от кода для float, если это не SSEx. Код для 64- и 32- битных плавающих числе отличается только в инициализации.
21.03.2012 10:58
Find all posts by this user Quote this message in a reply
kostya_76 Offline

Posts: 33
Post: #458

Подскажет кто-нибудь, почему триггер в данной функции срабатывает только со второй генерации случайной карты?

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

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

Зависимость от Эры не устраивает, т.к. скорее всего программа будет использоваться в ТЕ/WT.
21.03.2012 23:33
Find all posts by this user Quote this message in a reply
gamecreator Offline

Posts: 7107
Post: #459

кто-нибудь знает как получить указатель на массив героев?


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

Posts: 2180
Post: #460

Разная инфа хранится в разных массивах. Основной: *(_ptr_*)0x699538 + 0x21620 (размер элемента: 1170 байт).
22.03.2012 11:43
Find all posts by this user Quote this message in a reply
Sav Offline

Posts: 2180
Post: #461

В начале 2^32 - 1 раунда все непризванные стеки на поле боя погибнут (призванные сделают это в начале 2^32 - 1 раунда, считая с момента призыва). Это связано с полем, отвечающим за оставшиеся раунды жизни клонов, которое при инициализации -1, для клона отдельно устанавливается, и при уменьшении которого нет никаких проверок.
28.03.2012 16:37
Find all posts by this user Quote this message in a reply
Algor Away
Administrators

Posts: 3880
Post: #462

(28.03.2012 16:37)Sav Wrote:  В начале 2^32 - 1 раунда все непризванные стеки на поле боя погибнут
От черт.... значит нельзя бесконечно смотреть на 2х дерущихся троллей 118
Я кстати на df2 упоминал о подобном "переполнении" при споре, можно ли гарпией ведьмой при определенном сочетании препятствий на поле боя завалить 100500 бегемотов. Хотя, за миллиард ходов конкретно 100500 бегемотов лягут...


BattleHeroes Rus/Eng | ERA scripts (+ReMagic) Rus/Eng
28.03.2012 18:20
Visit this user's website Find all posts by this user Quote this message in a reply
Sav Offline

Posts: 2180
Post: #463

Ну, бегемоты-то всё равно умрут в результате. Sm
28.03.2012 19:25
Find all posts by this user Quote this message in a reply
gamecreator Offline

Posts: 7107
Post: #464

(28.03.2012 18:20)Algor Wrote:  От черт.... значит нельзя бесконечно смотреть на 2х дерущихся троллей 118
даже если раунд будет занимать 1 секунду, тебе хватит раундов для непрерывного просмотра в течении 136 лет Sm


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

Posts: 2180
Post: #465

Возможно, быстрая битва не предусматривает другого выхода из подобных ситуаций.
29.03.2012 23:06
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