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


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

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

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

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

Сообщение RoseKavalier » 03 фев 2021, 14:19

Yes, impressive work - I wouldn't have originally known how to get it without you! :smile20:
Вернуться к началу

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: Как создать плагин для HD мода

Сообщение AlexSpl » 03 фев 2021, 15:32

Сообщение при посещении Abandoned Mine:

Код: Выделить всё
int __stdcall showAbandonedMine(LoHook* h, HookContext* c)
{
    // Получаем состояние шахты
    _MapItem_* mapItem = (_MapItem_*)*(int*)(c->ebp + 8);
   
    // Если есть охрана
    if ( *(char*)(o_GameMgr->Field<int>(0x4E38C) + (mapItem->setup << 6)) < 0 )
    {
        // Если герой выбран
        if ( o_ActivePlayer->selected_hero_id > ID_NONE && o_ActivePlayer->selected_hero_id < 156 )
        {
            _Hero_* hero = o_GameMgr->GetHero(o_ActivePlayer->selected_hero_id);
            int heroArmyPower = CALL_1(int, __fastcall, 0x44A950, &hero->army);

            _Army_* defArmy = (_Army_*)(o_GameMgr->Field<int>(0x4E38C) + (mapItem->setup << 6) + 4);
            int defArmyPower = CALL_1(int, __fastcall, 0x44A950, defArmy);

            if ( defArmyPower ) // На всякий (чтобы избежать неожиданного деления на 0)
            {
                double k = (double)heroArmyPower / defArmyPower;
               
                // Вычисляем координаты входа
                int mapSize = o_AdvMgr->map->size;
                int pos = mapItem - o_AdvMgr->map->items;
                char x = pos % mapSize;
                pos /= mapSize;
                char y = pos % mapSize;
                char z = pos / mapSize;
                                                           
                // Получаем количество стеков, на которое разбилась охрана
                int stackCount = getStacksCount(k, x, y, z);
               
                // Выясняем, есть ли улучшенный стек
                char* upgStr = upgradedStack(k, x, y, z) ? "Yes" : "No";

                // Передаём адрес текстового буфера в качестве аргумента для диалога
                sprintf(o_TextBuffer, "%s\n\n%s: %d\n\n%s%d\n\n%s%s", (char*)c->ecx, o_CreatureInfo[defArmy->type[0]].name_plural, defArmy->count[0],
                    "# of stacks: ", getStacksCount(k, x, y, z), "Upgraded stack: ", upgStr);
                c->ecx = (int)o_TextBuffer;
            }
        }
    }
       
    return EXEC_DEFAULT;
}

...

_PI->WriteLoHook(0x4A36E4, showAbandonedMine); // Abandoned Mine

Проверку на героя можно убрать. Вывод информации на Ваше усмотрение.

Попробую покопаться в коде Пирамиды :smile1:

* * *
Посещение Пирамиды:

Код: Выделить всё
int __stdcall showPyramid(LoHook* h, HookContext* c)
{
    // Получаем состояние пирамиды
    _MapItem_* mapItem = (_MapItem_*)*(int*)(c->ebp + 0xC);
   
    // Если есть охрана
    if ( mapItem->setup & 1 )
    {
        // Если герой выбран
        if ( o_ActivePlayer->selected_hero_id > ID_NONE && o_ActivePlayer->selected_hero_id < 156 )
        {
            _Hero_* hero = o_GameMgr->GetHero(o_ActivePlayer->selected_hero_id);
            int heroArmyPower = CALL_1(int, __fastcall, 0x44A950, &hero->army);

            int defArmyPower = 20 * o_CreatureInfo[CID_DIAMOND_GOLEM].AI_value + 40 * o_CreatureInfo[CID_GOLD_GOLEM].AI_value;

            if ( defArmyPower ) // На всякий (чтобы избежать неожиданного деления на 0)
            {
                double k = (double)heroArmyPower / defArmyPower;
               
                // Вычисляем координаты входа
                int mapSize = o_AdvMgr->map->size;
                int pos = mapItem - o_AdvMgr->map->items;
                char x = pos % mapSize;
                pos /= mapSize;
                char y = pos % mapSize;
                char z = pos / mapSize;
                                                           
                // Получаем количество стеков, на которое разбилась охрана
                int stackCount = getStacksCount(k, x, y, z);

                stackCount -= 2;
                if ( stackCount < 1 ) stackCount = 1;

                // Передаём адрес текстового буфера в качестве аргумента для диалога
                sprintf(o_TextBuffer, "%s\n\n%s: %d\n%s: %d\n\n# of stacks of %s: %d", (char*)c->ecx, o_CreatureInfo[CID_DIAMOND_GOLEM].name_plural, 20,
                    o_CreatureInfo[CID_GOLD_GOLEM].name_plural, 40, o_CreatureInfo[CID_GOLD_GOLEM].name_plural, stackCount);
                c->ecx = (int)o_TextBuffer;
            }
        }
    }
       
    return EXEC_DEFAULT;
}

...

_PI->WriteLoHook(0x4A3EF5, showPyramid); // Pyramid
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

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

Сообщение Rolex » 03 фев 2021, 17:05

AlexSpl писал(а):

char y = (pos - z * mapSize * mapSize) / mapSize;

Исправил. Спасибо. Но причина падения не в этом была.

AlexSpl писал(а):

Попробуйте обернуть используемые структуры #pragma pack/pop.

Это делать я уже взял себе за правило. Но, видимо, в этом и была причина, так как с шахтой у вас парочка новых структур нарисовалась (_Hero_ и _Army_). Вот их обернул и стало все ок. Другие уже были обернуты.

AlexSpl писал(а):

Вы можете попробовать сами его доработать, чтобы он выводил информацию о кол-ве существ в каждом отряде (у Вас есть кол-во существ и кол-во стеков), а также учитывал тот случай, когда грейд есть, а отряд только один (в игре отряд неулучшенных нейтралов не может получить улучшенный стек при разбиении на 1 стек), и считал, в какой позиции окажется улучшенный стек (в FizMiG'е есть, вроде, но и так понятно, что посередине - при нечётном кол-ве отрядов и на полслота :smile1: ниже - при чётном). Также этот код легко доработать, чтобы он показывал аналогичную информацию о разбиении нейтралов на стеки.


Доработал. Заменил вот это:
Код: Выделить всё
// Передаём адрес текстового буфера в качестве аргумента для диалога
sprintf(o_TextBuffer, "%s\n\n%s: %d\n\n%s%d\n\n%s%s", (char*)c->ecx, o_CreatureInfo[defArmy->type[0]].name_plural, defArmy->count[0],
"# of stacks: ", getStacksCount(k, x, y, z), "Upgraded stack: ", upgStr);
c->ecx = (int)o_TextBuffer;


на это:
Код: Выделить всё
string str = (char*)c->ecx; // Оригинальное сообщение
                  str += "\n";
                  
                  int position = 0;

                  for (int i = 0; i < defArmy->count[0] % stackCount; ++i)
                  {
                     position++;
                     if (upgStr == "Yes" && position == stackCount / 2 + 1) str = str + "\n" + "Адские " + o_CreatureInfo[defArmy->type[0]].name_plural + ": "; else
                        str = str + "\n" + o_CreatureInfo[defArmy->type[0]].name_plural + ": ";
                        
                         str = str + to_string(defArmy->count[0] / stackCount + 1);
                  }


                  for (int i = 0; i < stackCount - (defArmy->count[0] % stackCount); ++i)
                  {
                     position++;
                     if (upgStr == "Yes" && position == stackCount / 2 + 1) str = str + "\n" + "Адские " + o_CreatureInfo[defArmy->type[0]].name_plural + ": "; else
                        str = str + "\n" + o_CreatureInfo[defArmy->type[0]].name_plural + ": ";
                        
                         str = str + to_string(defArmy->count[0] / stackCount);
                  }
                  

                  // Передаём адрес текстового буфера в качестве аргумента для диалога
                  sprintf(o_TextBuffer, "%s", str.c_str());
                  

                  c->ecx = (int)o_TextBuffer;


Все разбивает отлично.
Правда для грейженных пришлось дописывать приставку "Адские ", но, видимо, можно как-то через структуру более правильно это сделать.
Последний раз редактировалось Rolex 03 фев 2021, 17:48, всего редактировалось 2 раз(а).
Вернуться к началу

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: Как создать плагин для HD мода

Сообщение AlexSpl » 03 фев 2021, 17:17

Цитата:
Правда для грейженных пришлось дописывать приставку "Адские ", но, видимо, можно как-то через структуру более правильно это сделать.

Есть функция, которая возвращает грейд монстра: CALL_1(int, __fastcall, 0x47AAD0, monID); Тогда должно быть так: o_CreatureInfo[CALL_1(int, __fastcall, 0x47AAD0, defArmy->type[0])].name_plural

Цитата:
А подскажите, пжл, как добавить эту уже сделанную разбивку на отряды в диалог при посещении шахты (Хотите спустится? ДА / НЕТ)? Как с банками и жилищами делают функции showGuards и showMonsters?

Выше написал.

Ещё нужно от диалога избавляться при посещении разграбленной Пирамиды. Код будет такой же, как и для Склепа, но с другими адресами, по идее. Для сообщения по правому клику код можно перенести в showGuardsRMB() с проверкой на тип объекта.

* * *
Такой момент есть ещё: если кому-то будет нужен код, который будет показывать разбивку нейтралов, то не забудьте о случае, когда нейтралов меньше, чем стеков, на которые они должны поделиться.
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

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

Сообщение Rolex » 03 фев 2021, 17:38

С Abandoned Mine теперь все ок. А вот для Пирамиды по ПКМ, чтобы код из showPyramid заработал нужен адрес Пирамиды, как объекта: mapItem->object_type ==0x??

AlexSpl писал(а):

Ещё нужно от диалога избавляться при посещении разграбленной Пирамиды. Код будет такой же, как и для Склепа, но с другими адресами, по идее.

Тот код igrik'а работает не только для Склепа, а еще и для Кораблей. Но для Пирамиды, увы, нужно писать другой...

AlexSpl писал(а):

Такой момент есть ещё: если кому-то будет нужен код, который будет показывать разбивку нейтралов, то не забудьте о случае, когда нейтралов меньше, чем стеков, на которые они должны поделиться.

Точно! Нужно доработать свой код. Кто-то рубился и слился. :smile12:
Последний раз редактировалось Rolex 03 фев 2021, 17:54, всего редактировалось 2 раз(а).
Вернуться к началу

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: Как создать плагин для HD мода

Сообщение AlexSpl » 03 фев 2021, 17:52

Цитата:
С Abandoned Mine теперь все ок. А вот для Пирамиды по ПКМ, чтобы код из showPyramid заработал нужен адрес Пирамиды, как объекта: mapItem->object_type ==0x??

0x3F

Цитата:
Но для Пирамиды, увы, нужно писать другой...


Код: Выделить всё
int __stdcall Pyramid_SkipMsgIfVisited(LoHook* h, HookContext* c)
{
   if ( *(int*)*(int*)(c->ebp + 0xC) & 0x2000000 )
   {
      c->return_address = 0x4A3F22;
      return NO_EXEC_DEFAULT;
   }

   return EXEC_DEFAULT;
}

...

// Пропускаем сообщения для Пирамиды, если она посещена
_PI->WriteLoHook(0x4A3ED3, Pyramid_SkipMsgIfVisited);


Ой. Так все пропускаются...
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

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

Сообщение Rolex » 03 фев 2021, 18:08

AlexSpl писал(а):

Ой. Так все пропускаются...

Ага, сразу в бой кидает.

И у меня почему-то вылетает по ПКМ по Пирамиде, когда добавил код из showPyramid в showGuardsRMB с проверкой на тип объекта:

Код: Выделить всё
      // Пирамида
      if (mapItem->object_type == 0x3F)
      {
         // Получаем состояние пирамиды
         _MapItem_* mapItem = (_MapItem_*)*(int*)(c->ebp + 0xC);

         // Если есть охрана
         if (mapItem->setup & 1)
         {
            // Если герой выбран
            if (o_ActivePlayer->selected_hero_id > ID_NONE && o_ActivePlayer->selected_hero_id < 156)
            {
               _Hero_* hero = o_GameMgr->GetHero(o_ActivePlayer->selected_hero_id);
               int heroArmyPower = CALL_1(int, __fastcall, 0x44A950, &hero->army);

               int defArmyPower = 20 * o_CreatureInfo[CID_DIAMOND_GOLEM].AI_value + 40 * o_CreatureInfo[CID_GOLD_GOLEM].AI_value;

               if (defArmyPower) // На всякий (чтобы избежать неожиданного деления на 0)
               {
                  double k = (double)heroArmyPower / defArmyPower;

                  // Вычисляем координаты входа
                  int mapSize = o_AdvMgr->map->size;
                  int pos = mapItem - o_AdvMgr->map->items;
                  char x = pos % mapSize;
                  pos /= mapSize;
                  char y = pos % mapSize;
                  char z = pos / mapSize;

                  // Получаем количество стеков, на которое разбилась охрана
                  int stackCount = getStacksCount(k, x, y, z);

                  stackCount -= 2;
                  if (stackCount < 1) stackCount = 1;

                  // Передаём адрес текстового буфера в качестве аргумента для диалога
                  sprintf(o_TextBuffer, "%s\n\n%s: %d\n%s: %d\n\n# of stacks of %s: %d", (char*)c->ecx, o_CreatureInfo[CID_DIAMOND_GOLEM].name_plural, 20,
                     o_CreatureInfo[CID_GOLD_GOLEM].name_plural, 40, o_CreatureInfo[CID_GOLD_GOLEM].name_plural, stackCount);
                  c->ecx = (int)o_TextBuffer;
               }
            }
         }
      }
Вернуться к началу

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: Как создать плагин для HD мода

Сообщение AlexSpl » 03 фев 2021, 18:17

Понятия не имею, почему для Пирамиды не работает (может, IsVisited() сложнее, чем & 0x2000000) :smile5:

Вот другой код:

Код: Выделить всё
int __stdcall Pyramid_SkipMsgIfVisited(LoHook* h, HookContext* c)
{
   // Получаем состояние пирамиды
   _MapItem_* mapItem = (_MapItem_*)*(int*)(c->ebp + 0xC);

   if ( mapItem->setup & 1 ) return EXEC_DEFAULT;
   
   c->return_address = 0x4A3F22;
   return NO_EXEC_DEFAULT;
}

Так, разобрался, в примере с посещением (& 0x2000000) я наоборот всё сделал :smile1: Там, похоже флаг посещения выше устанавливается, но охрана у объекта всё ещё есть. Поэтому диалог скипается и начинается бой :smile1:

* * *
Цитата:
// Получаем состояние пирамиды
_MapItem_* mapItem = (_MapItem_*)*(int*)(c->ebp + 0xC);

Это здесь не нужно. mapItem мы получаем другим способом.
Последний раз редактировалось AlexSpl 03 фев 2021, 18:31, всего редактировалось 1 раз.
Вернуться к началу

offlineRolex  
имя: Alex
Ветеран
Ветеран
 
Сообщения: 898
Зарегистрирован: 22 сен 2020, 18:58
Откуда: УКРАИНА
Пол: Мужчина
Поблагодарили: 53 раз.

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

Сообщение Rolex » 03 фев 2021, 18:30

AlexSpl писал(а):

Так, разобрался, в примере с посещением (& 0x2000000) я наоборот всё сделал

Ну код выше вроде как работает норм. А если переписать на (& 0x2000000) разницы в работе не будет, только в реализации?
Вернуться к началу

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: Как создать плагин для HD мода

Сообщение AlexSpl » 03 фев 2021, 18:32

Да, не должно: Visited = отсутствие охраны.

Цитата:
Там, похоже флаг посещения выше устанавливается, но охрана у объекта всё ещё есть. Поэтому диалог скипается и начинается бой

Хотя нет. Ерунда какая-то с посещением & 0x2000000 :smile5:
Вернуться к началу

Пред.След.

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

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

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