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


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

Как создать плагин для HD мода

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

Re: Как создать плагин для HD мода

Сообщение RoseKavalier » 27 мар 2019, 15:41

Код: Выделить всё
#define IsGuarded(x,y,z) (0x0100 & CALL_3(WORD, __fastcall, 0x4F8040, x, y, z))

is BOOL type, it simply tells you if tile (x,y,z) is under protection of a monster.

If IsGuarded returns TRUE, then you would have to look around to find on which tile there is a guardian, that is xyz_54 is packed coordinates.
It's really just about optimising code a bit, igrik's formula still does the job fine.
Вернуться к началу

offlineigrik  
Подмастерье
Подмастерье
 
Сообщения: 108
Зарегистрирован: 14 сен 2017, 12:35
Пол: Не указан
Поблагодарили: 84 раз.

Re: Как создать плагин для HD мода

Сообщение igrik » 28 мар 2019, 14:02

as239 писал(а):

Вопрос к igrik по плагину "защита объектов".
На какие адреса нужно еще поставить хуки для защиты ресурсов, сундуков, костра и ученого?

Я переписал код, чтобы не ставить уеву тучу хуков.

Код: Выделить всё
//   ФУНКЦИЯ: есть ли стража рядом с объектом (возвращает координаты клетки с монстрами)
_int_ isGuardNearTheObject(_AdvMgr_* advMng, _int_ xyz)
{
   int xd = b_unpack_x(xyz);
   int yd = b_unpack_y(xyz);
   int z = b_unpack_z(xyz);

   if (!(0x0100 & CALL_3(WORD, __fastcall, 0x4F8040, xd, yd, z)) ) {
      return 0; // монстров вокруг клетки нет
   }

   int x, y;
   int size = advMng->map->size;
   // ряд на уровне арта --------------------------------------------------------------------------------------
   x = xd -1; y = yd;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }

   x = xd +1; y = yd;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }
   // ряд ниже арта --------------------------------------------------------------------------------------------
   x = xd -1; y = yd +1;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }

   x = xd;   y = yd +1;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }

   x = xd +1; y = yd +1;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }

   // ряд выше арта --------------------------------------------------------------------------------------------     
   x = xd -1; y = yd -1;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }

   x = xd; y = yd -1;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }

   x = xd +1; y = yd -1;
   if ( x >= 0 && x < size && y >= 0 && y < size) {
      if (advMng->map->GetItem(x,y,z)->object_type == 54) {
            return b_pack_xyz(x,y,z); } }
   // -----------------------------------------------------------------------------------------------------
   return 0; // монстров вокруг клетки нет
}

// при движении мыши на КП
_int_ __stdcall Y_GetCursorFrameOnAdvMap(HiHook* hook, _AdvMgr_* advMng, _MapItem_* obj)
{
   switch (obj->object_type) {
      case 5: case 6: case 12: case 79: case 81: case 82: case 93: case 101:  // типы защищаемых объектов
         if ( isGuardNearTheObject(advMng, advMng->pack_xyz) ) {
            return 5; // возвращаем боевой курсор
         }   break;

      default: break;
   }
   return CALL_2(_int_, __thiscall, hook->GetDefaultFunc(), advMng, obj);
}

void __stdcall Y_Hero_Enter_To_Object(HiHook* hook, _AdvMgr_* advMng, _Hero_* hero, _MapItem_* obj, _int_ xyz, _int_ isPlayer)
{
   int xyz_54 = 0; // инициализации переменной - координаты охранников

   switch (obj->object_type) {
      case 5: case 6: case 12: case 79: case 81: case 82: case 93: case 101:  // типы защищаемых объектов
         xyz_54 = isGuardNearTheObject(advMng, xyz); // проверка стражи объекта в соседних клетках
         if ( xyz_54 ){  // если стража есть
            _MapItem_* obj_54 = advMng->map->GetItem(b_unpack_x(xyz_54), b_unpack_y(xyz_54), b_unpack_z(xyz_54)); // получаем структуру объекта "стража"
            advMng->monBattle_type = (_word_)obj_54->os_type; // (advMng+<536>)
            advMng->monBattle_num = (_word_)obj_54->draw_num; // (advMng+<540>)
            advMng->monBattle_side = hero->x < (_word_)((_word_)(xyz_54 << 6) >> 6) ? 1 : 0; // поворот монстра при атаке (advMng+<544>)

            CALL_5(void, __thiscall, 0x4A73B0, advMng, obj_54, hero, xyz_54, isPlayer); // нападаем на монстра рядом с артом

            advMng->monBattle_type = -1; // после битвы возвращаем параметры
            advMng->monBattle_num = -1;  // после битвы возвращаем параметры
            if (hero->owner_id < 0) {    // если герой убит или сбежал (т.е. номер хозяина героя стал == -1)
               return; // выйти из функции ПОСЕЩЕНИЕ ОБЪЕКТА
            }
         }   break;

      default: break;
   }

   CALL_5(void, __thiscall, hook->GetDefaultFunc(), advMng, hero, obj, xyz, isPlayer);
   return;
}


/////////////////////////////////////////////////////////////////////////////////////
_PI->WriteHiHook(0x40E97F, CALL_, EXTENDED_, THISCALL_, Y_GetCursorFrameOnAdvMap);
_PI->WriteHiHook(0x4AA766, CALL_, EXTENDED_, THISCALL_, Y_Hero_Enter_To_Object);


upd: для уменьшения нагрузки добавлена предложенная RoseKavalier функция 0x4F8040
Последний раз редактировалось igrik 28 мар 2019, 14:54, всего редактировалось 1 раз.
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

Re: Как создать плагин для HD мода

Сообщение as239 » 28 мар 2019, 14:30

Проверил, в самой игре все ок, но при выходе в главное меню вылет.
Дело точно в хайхуке Y_Hero_Enter_To_Object, потому что без него все ок.
Вернуться к началу

offlineigrik  
Подмастерье
Подмастерье
 
Сообщения: 108
Зарегистрирован: 14 сен 2017, 12:35
Пол: Не указан
Поблагодарили: 84 раз.

Re: Как создать плагин для HD мода

Сообщение igrik » 28 мар 2019, 14:55

Ты уверен? Я хз, потому что у меня не вылетает при выходе в главное меню.
Но я тестирую всё на ERA...
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

Re: Как создать плагин для HD мода

Сообщение as239 » 28 мар 2019, 15:23

Да точно воспроизводится, тестирую на SOD, нужно взять хоть один защищенный объект и при выходе в главное меню вылет.
Module: Heroes3 HD.exe
Adress: [ 0x004079B2 ]
Code: EXCEPTION_ACCESS_VIOLATION
Flags: 0x00000000
Information: read of address: 0xFFFFFFFF
Если вернуть старый код или отключить хук то все ок.
Вернуться к началу

offlineigrik  
Подмастерье
Подмастерье
 
Сообщения: 108
Зарегистрирован: 14 сен 2017, 12:35
Пол: Не указан
Поблагодарили: 84 раз.

Re: Как создать плагин для HD мода

Сообщение igrik » 28 мар 2019, 17:09

Я поставил SoD и протестировал раз 10 в разных вариантах нападения на защищаемые объекты - вылетов нет. Поэтому я не могу ответить что не так.
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

Re: Как создать плагин для HD мода

Сообщение as239 » 28 мар 2019, 17:30

Полностью скопировал свойства структуры _AdvMgr_ и теперь все стало ок, большое спасибо!
Вот здесь была другая размерность:
_byte_ field_60[136]; //+96
Вернуться к началу

offlineas239  
имя: Анатолий
Ветеран
Ветеран
 
Сообщения: 527
Зарегистрирован: 29 дек 2018, 14:17
Пол: Мужчина
Поблагодарили: 38 раз.

Re: Как создать плагин для HD мода

Сообщение as239 » 29 мар 2019, 06:00

За время тестирования обратил внимание насколько же часто генерятся багнутые по дорогам сдачи.
Т.е. дорога от деревни респа идет на другой респ, а не в центральный город.
Никто не знает адрес где происходит построение дорог?
Если бы можно было поставить хук, в котором есть город от которого идет дорога и город к которому идет дорога.
То для шаблона JC получается совсем простой алгоритм проверки этой пары и корректировки в случае необходимости.
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

Re: Как создать плагин для HD мода

Сообщение RoseKavalier » 29 мар 2019, 21:19

sub_005328A0 writes the road type to a tile during RMG.

Код: Выделить всё
_RMGMapItem_ *__thiscall RMG_WriteRoad_005328A0(PtrToRMGStructOffset *this, POINT *a2, char roadType)
{
  _RMGMapItem_ *result; // eax

  result = &this->miOffset->mapItems[a2->x + a2->y * this->miOffset->sizeX];
  result->PackedGroundData = result->PackedGroundData & ~0x3C000000 | ((roadType & 0xF) << 26);
  return result;
}


The format of PackedGroundData is bitfield as follows
Код: Выделить всё
struct RMG_GroundTile
{
   unsigned landType   : 5; // bit 1~4
   unsigned _b6      : 1;
   unsigned landSprite : 7; // bit 7 ~ 13
   unsigned _b14      : 1;
   unsigned riverType   : 3; // bit 15, 16, 17
   unsigned _b18      : 1;
   unsigned riverSprite : 7;// bit 19, 20, 21, 22, 23, 24, 25
   unsigned _b26      : 1;
   unsigned roadType   : 3; // bit 27 28 29
   unsigned _b30      : 3;
};


In PackedGroundData2 you have another bitfield, but I did not map it beyond this:
Код: Выделить всё
struct RMG_GroundTileData
{
   unsigned roadSprite : 7;
   unsigned _b8 : 8;
   unsigned mirrorLandV : 1;   // bit 16 [0x0000 8000]
   unsigned mirrorLandH : 1;   // bit 17 [0x0001 0000]
   unsigned mirrorRiverV : 1;   // bit 18 [0x0002 0000]
   unsigned mirrorRiverH : 1;   // bit 19 [0x0004 0000]
   unsigned mirrorRoadV : 1;   // bit 20 [0x0008 0000]
   unsigned mirrorRoadH : 1;   // bit 21 [0x0010 0000]
   unsigned shore : 1;         // bit 22 [0x0020 0000]~ unsure, written to h3m at 0x532E42
   unsigned _access : 10; // these seem to be used to determine access of tile on map
};


After looking at code a little bit, it seems to me that a better place to try to fix road blocks (and other RMG issues), outside of completely disassembling the RMG function itself, is before _RMGStruct_ is written to H3M file.
The function call to write occurs at 0x54C54B, in _RMGStruct_ you have access to _RMG_MapItem_ as in the sub above which contains land type, road type and access, and some more. Given that H3M format is well known, it should not be too hard to figure out all necessary information from this spot with some work.
Последний раз редактировалось RoseKavalier 30 мар 2019, 13:43, всего редактировалось 1 раз.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1318
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 30 мар 2019, 05:50

And how should be changed Monsters positions at 0x54C54B ? I mean how to get access to Monsters x, y, z.

And besides, while using _RMGStruct_* how should be rewritten this part ?

Код: Выделить всё
    objectsNumber = ((int)o_GameMgr->Map.Objects.EndData - (int)o_GameMgr->Map.Objects.Data)/12;
    for(int n = 0; n < objectsNumber; n++)
    {
        templateId = o_GameMgr->Map.Objects[n].template_id;
        ...
        impassNumber = (int)o_GameMgr->Map.Templates[templateId].ImpassBitMask.bits0;


Or
Код: Выделить всё
RMGMapItem->PackedGroundData2->_access
is sufficient (by analogy with MapItem->attrib) ?
Последний раз редактировалось Ben80 30 мар 2019, 10:31, всего редактировалось 3 раз(а).
Вернуться к началу

Пред.След.

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

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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2