Объявления
Поздравляем
Roman2211


Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

База данных IDA от void17

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 25 ноя 2021, 04:42

AlexSpl писал(а):

Разбираю конструктор type_AI_spellcaster::type_AI_spellcaster(). Пришлось после того, как увидел оценку заклинания Fire Shield. Так вот, размер этого класса 1040 байт.

Я тоже так сначала подумал, вы попались в ту же ловушку, в которую попал и я месяц назад, изучая это дело. Размер мною был определен правильно, там просто массив или что-то другое, но впринципе ее размер гораздо меньше.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 25 ноя 2021, 05:01

Вот такой класс type_AI_spellcaster:

Код: Выделить всё
00000000 type_AI_spellcaster struc ; (sizeof=0x410, align=0x4, mappedto_367)
00000000                                                             ; XREF: FF015AA0/r
00000000 VMT       dd ?                                              ; offset
00000004 Hero      dd 2 dup(?)                                       ; offset
0000000C Side      dd 2 dup(?)
00000014 field_14  dd ?
00000018 field_18  dd ?
0000001C hexDeadArmyOrWarMachine db ?
0000001D field_1D  db ?
0000001E field_1E  db ?
0000001F field_1F  db ?
00000020 attack    dd ?                                              ; offset
00000024 defense   dd ?
00000028 IsFightValueCapped dd ?
0000002C field_2C  dd ?
00000030 field_30  dd ?
00000034 field_34  dd ?
00000038 field_38  dd ?
0000003C monster   dd ?                                              ; offset
00000040 field_40  dd ?
00000044 field_44  dd ?
00000048 spellcaster dd ?                                            ; offset
0000004C field_4C  dd ?
00000050 field_50  dd 80 dup(?)
00000190 field_190 dd 80 dup(?)
000002D0 field_2D0 dd 80 dup(?)
00000410 type_AI_spellcaster ends

Позже посмотрю типы элементов этих трёх массивов на 80 двордов.

Цитата:
Размер мною был определен правильно, там просто массив или что-то другое, но впринципе ее размер гораздо меньше.

Почему? К какому полю тогда обращается int __thiscall type_AI_spellcaster::get_fire_shield_value(type_AI_spellcaster *this, const army *Army, type_enchant_data EnchantData) вот тут: x = this->field_50[4 * Army->Index];
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 25 ноя 2021, 05:08

Если разбить по 80, тогда имеет смысл. Это количество заклинаний. А у вас их явно больше 80. Придется полностью переписывать AI для добавления новых заклинаний. Будем вместе переписывать .cpp/.h файлы.

А оттуда, можно использовать и в плагинах и заменить оригинальное на наше.
 
Может заменить их на vector?
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 25 ноя 2021, 05:10

Кстати нужно разобрать type_AI_combat_parameters. Вот с этим классом у меня много сомнений.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 25 ноя 2021, 05:11

Точнее, если интересно:

Код: Выделить всё
stack = (army *)this->field_50[4 * Army->Index];
  if ( !stack || (stack->Flags & FIREIMMUNITY) != 0 )
    return 0;

Т.е. по 4 байта на 20 отрядов. Ой, там же 80 двордов. Точнее по 16 байтов или 4 дворда.

И до этого есть вот что:

Код: Выделить всё
v23 = this->field_50[4 * Army->Index + 2];

а потом
Код: Выделить всё
damage = average_damage + v23 * (_DWORD)*p_Army;

Т.е. добавочный урон ещё там хранится.
Последний раз редактировалось AlexSpl 25 ноя 2021, 05:22, всего редактировалось 1 раз.
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 25 ноя 2021, 05:20

Жаль, закрепить нельзя. Предлагаю такие префиксы для enum-ов:
SPL — тип заклинания,
SF — флаги заклинаний
CT — тип существа,
CF — флаги существ,
HT — тип героя,
HF — флаги героя,
SS — вторичный навык,
SSL — ступень вторичного навыка,
PS — первичный навык
AO — тип объекта на карте
Последний раз редактировалось void_17 25 ноя 2021, 06:10, всего редактировалось 1 раз.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 25 ноя 2021, 05:22

Я выбрал для спеллов SPL_, уже переделал :smile1:

А вот эта функция из конструктора проливает свет на назначение второго и третьего дворда:
Код: Выделить всё
void __thiscall sub_0043BB70(type_AI_spellcaster *this)
{
  type_AI_spellcaster *AI_spellcaster; // edx
  army *Army; // esi
  int *v3; // ebx
  ECreatureType Type; // eax
  army *AI_target; // edi
  int Speed; // eax
  int average_damage; // eax
  int iArmy; // [esp+8h] [ebp-8h]

  AI_spellcaster = this;
  Army = gpCombatManager->Army[this->Side[0]];
  memset(this->field_50, 0, sizeof(this->field_50));
  iArmy = 0;
  if ( gpCombatManager->ArmyNum[this->Side[0]] > 0 )
  {
    v3 = &this->field_50[1];
    do
    {
      if ( !Army->SpellDuration[SPL_BLIND]
        && !Army->SpellDuration[SPL_STONE_GAZE]
        && !Army->SpellDuration[SPL_PARALYZE]
        && (Army->Flags & CANNOTMOVE) == 0 )
      {
        Type = Army->Type;
        if ( Type != _FIRST_AID_TENT_ && Type != _AMMO_CART_ && !Army->SpellDuration[SPL_HYPNOTIZE] )
        {
          AI_target = Army->AI_target;
          if ( AI_target )
          {
            if ( !army::can_shoot(Army, 0) )
            {
              Speed = army::GetSpeed(Army);
              if ( combatMonster_004488F0_Balista_ArrowTower(Army, Speed) <= 1 )
              {
                *(v3 - 1) = (int)AI_target;
                average_damage = army::get_average_damage(AI_target, Army, 0, AI_target->AmountAlive, 0, 0);
                *v3 = average_damage;
                v3[2] = average_damage;
                v3[1] = 1;
              }
            }
            AI_spellcaster = this;
          }
        }
      }
      v3 += 4;
      ++iArmy;
    }
    while ( iArmy < gpCombatManager->ArmyNum[AI_spellcaster->Side[0]] );
  }
}

Кстати, this->Side[0] у type_AI_spellcaster можно смело переименовывать в CasterSide, a Side[1] - в EnemySide, потому что тут всё строго, а не так как в combatManager, т.е. кастующий AI всегда с индексом 0, а его противник - с 1.

Хотя... Не стоит. Мало ли по EnemySide где-то в коде получается CasterSide (типа, 1 - side). Будет некрасивый код. Лучше добавить enum на два значения: AI_CASTER, AI_ENEMY, например.
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 25 ноя 2021, 06:09

Мне лично массивы не нравятся :smile3: . Я пишу side1, side2, так нагляднее, потому что нумерация массива с нуля. Нуль смущает, ощущение, как будто неправильно что-то. На самом деле все ок, просто особенность указателей.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 25 ноя 2021, 07:54

Ну вот, теперь можно понять назначение почти всех полей type_AI_spellcaster:

Код: Выделить всё
void __thiscall type_AI_spellcaster_Init_43BC90(type_AI_spellcaster *this)
{
  int side; // eax
  combatManager *pCombatManager; // esi
  army *Army; // edx
  int *__shifted(type_AI_spellcaster,0x19C) pArmyInfo_B; // edi
  int sideEnemy; // eax
  army *EnemyArmy; // esi
  ECreatureType Type; // eax
  int average_damage; // eax
  int adjusted_damage; // edx
  int average_damage_B; // ecx
  int average_damage_0; // eax
  int avgDamage; // edx
  int average_damage_A; // ecx
  bool iArmy_B; // cc
  int *__shifted(type_AI_spellcaster,0x2D4) pArmyInfo_C; // eax
  int *AI_ArmyInfo_C; // ecx
  army *v18; // [esp+Ch] [ebp-10h]
  int iArmy_A; // [esp+10h] [ebp-Ch]
  int iArmy_C; // [esp+10h] [ebp-Ch]
  int iArmy; // [esp+14h] [ebp-8h]
  army *Target; // [esp+18h] [ebp-4h]

  this->bitfield_18 = 0;
  this->bitfield_14 = 0;
  memset(this->AI_ArmyInfo_C, 0, sizeof(this->AI_ArmyInfo_C));
  memset(this->AI_ArmyInfo_B, 0, sizeof(this->AI_ArmyInfo_B));
  type_AI_spellcaster_Init_43BB70(this);
  side = this->Side[AI_CASTER];
  pCombatManager = gpCombatManager;
  iArmy_A = 0;
  Army = gpCombatManager->Army[side];
  Target = Army;
  if ( gpCombatManager->ArmyNum[side] <= 0 )
    goto label_FillArmyInfo_C;
  // Shifted pointer for B
  pArmyInfo_B = &this->AI_ArmyInfo_B[3];
  do
  {
    if ( (Army->Flags & CANNOTMOVE) != 0 || Army->Type == CID_ARROW_TOWER )
      goto LABEL_26;
    sideEnemy = this->Side[AI_ENEMY];
    iArmy = 0;
    EnemyArmy = pCombatManager->Army[sideEnemy];
    v18 = ADJ(pArmyInfo_B)->AI_ArmyInfo_A[0];
    if ( gpCombatManager->ArmyNum[sideEnemy] <= 0 )
      goto LABEL_25;
    do
    {
      if ( !EnemyArmy->SpellDuration[SPL_BLIND]
        && !EnemyArmy->SpellDuration[SPL_STONE_GAZE]
        && !EnemyArmy->SpellDuration[SPL_PARALYZE]
        && (EnemyArmy->Flags & CANNOTMOVE) == 0 )
      {
        Type = EnemyArmy->Type;
        if ( Type != CID_FIRST_AID_TENT
          && Type != CID_AMMO_CART
          && !EnemyArmy->SpellDuration[SPL_HYPNOTIZE]
          && Type != CID_ARROW_TOWER
          && army::get_total_hit_points(EnemyArmy, 1) )
        {
          if ( army::can_shoot(EnemyArmy, 0) )
          {
            average_damage = army::get_average_damage(EnemyArmy, Target, 1, EnemyArmy->AmountAlive, 0, 0);
            adjusted_damage = average_damage + ADJ(pArmyInfo_B)->AI_ArmyInfo_B[3];
            ++ADJ(pArmyInfo_B)->AI_ArmyInfo_B[2];
            average_damage_B = ADJ(pArmyInfo_B)->AI_ArmyInfo_B[1];
            ADJ(pArmyInfo_B)->AI_ArmyInfo_B[3] = adjusted_damage;
            if ( average_damage > average_damage_B )
            {
              ADJ(pArmyInfo_B)->AI_ArmyInfo_B[1] = average_damage;
              ADJ(pArmyInfo_B)->AI_ArmyInfo_B[0] = EnemyArmy;
            }
LABEL_22:
            this->bitfield_14 |= 1 << EnemyArmy->Index;
            goto LABEL_23;
          }
          if ( EnemyArmy != v18 && ((1 << iArmy_A) & EnemyArmy->field_544) != 0 )
          {
            this->bitfield_18 |= 1 << iArmy;
            average_damage_0 = army::get_average_damage(EnemyArmy, Target, 0, EnemyArmy->AmountAlive, 0, 0);
            avgDamage = average_damage_0 + ADJ(pArmyInfo_B)->AI_ArmyInfo_A[3];
            ++ADJ(pArmyInfo_B)->AI_ArmyInfo_A[2];
            average_damage_A = ADJ(pArmyInfo_B)->AI_ArmyInfo_A[1];
            ADJ(pArmyInfo_B)->AI_ArmyInfo_A[3] = avgDamage;
            if ( average_damage_0 > average_damage_A )
            {
              ADJ(pArmyInfo_B)->AI_ArmyInfo_A[1] = average_damage_0;
              ADJ(pArmyInfo_B)->AI_ArmyInfo_A[0] = EnemyArmy;
            }
            goto LABEL_22;
          }
        }
      }
LABEL_23:
      ++EnemyArmy;
      ++iArmy;
    }
    while ( iArmy < gpCombatManager->ArmyNum[this->Side[AI_ENEMY]] );
    Army = Target;
LABEL_25:
    pCombatManager = gpCombatManager;
LABEL_26:
    pArmyInfo_B += 4;
    ++Army;
    iArmy_B = ++iArmy_A < pCombatManager->ArmyNum[this->Side[AI_CASTER]];
    Target = Army;
  }
  while ( iArmy_B );
label_FillArmyInfo_C:
  // Заполняем массив C
  iArmy_C = 0;
  if ( pCombatManager->ArmyNum[this->Side[AI_CASTER]] > 0 )
  {
    // Shifted pointer for C
    pArmyInfo_C = &this->AI_ArmyInfo_C[1];
    do
    {
      AI_ArmyInfo_C = ADJ(pArmyInfo_C)->AI_ArmyInfo_C;
      ADJ(pArmyInfo_C)->AI_ArmyInfo_C[0] = ADJ(pArmyInfo_C)->AI_ArmyInfo_A[0];
      ADJ(pArmyInfo_C)->AI_ArmyInfo_C[1] = ADJ(pArmyInfo_C)->AI_ArmyInfo_A[1];
      ADJ(pArmyInfo_C)->AI_ArmyInfo_C[2] = ADJ(pArmyInfo_C)->AI_ArmyInfo_A[2];
      ADJ(pArmyInfo_C)->AI_ArmyInfo_C[3] = ADJ(pArmyInfo_C)->AI_ArmyInfo_A[3];
      if ( ADJ(pArmyInfo_C)->AI_ArmyInfo_B[1] > ADJ(pArmyInfo_C)->AI_ArmyInfo_C[1] )
      {
        *AI_ArmyInfo_C = ADJ(pArmyInfo_C)->AI_ArmyInfo_B[0];
        ADJ(pArmyInfo_C)->AI_ArmyInfo_C[1] = ADJ(pArmyInfo_C)->AI_ArmyInfo_B[1];
        AI_ArmyInfo_C[2] = ADJ(pArmyInfo_C)->AI_ArmyInfo_B[2];
        AI_ArmyInfo_C[3] = ADJ(pArmyInfo_C)->AI_ArmyInfo_B[3];
      }
      pArmyInfo_C += 4;
      ++iArmy_C;
    }
    while ( iArmy_C < gpCombatManager->ArmyNum[this->Side[AI_CASTER]] );
  }
}
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 25 ноя 2021, 08:25

Это не init и не конструктор. Это void type_AI_spellcaster::find_enemy_attacks();
Там вначале функция void type_AI_spellcaster::set_melee_enemies(); по адресу 0x43BB70
Скопируйте и вставьте в название функции(клавиша N по функции) это:
Код: Выделить всё
?find_enemy_attacks@type_AI_spellcaster@@IAAXXZ имя функции по адресу 0x43BC90
?set_melee_enemies@type_AI_spellcaster@@IAAXXZ имя функции по адресу 0x43BB70

IDA автоматически сдеманглит их в приличный вид.

Кстати. Лучше убрать shifted pointers. Это бывает удобно, но потом сложно переносить код в реальный C++ исполняемый файл.

Работа, конечно, впечатляет. Всего неделю назад загрузил базу, а уже во какой прогресс. Я знал, что мой труд окупится. Физмиг пополнится хорошечно этой зимой, чую я...
Вернуться к началу

Пред.След.

Вернуться в Общий раздел

Кто сейчас на конференции

Сейчас этот форум просматривают: GoGo.Ru [Bot] и гости: 3