Объявления

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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
Catastrophe  
имя: Alex
Посвященный
Посвященный
 
Сообщения: 88
Зарегистрирован: 07 мар 2019, 11:50
Пол: Мужчина
Поблагодарили: 22 раз.

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

Сообщение Catastrophe » 31 май 2019, 16:54

Расширенный ПКМ по нейтралам (заклинание видений не требуется для всего, кроме нижней строки и точного кол-ва существ)
 может потребоваться редактирование GENRLTXT.txt чтобы все влезало
Изображение

Код: Выделить всё
#include "homm3.h"

int c_neu_rmb_id;

int __stdcall c_get_neu_rmb(LoHook* h, HookContext* c)
{   
   c_neu_rmb_id = c->esi;

   return EXEC_DEFAULT;
}

int __stdcall c_neu_rmb_public(LoHook* h, HookContext* c)

   int c_neu_lv = o_pCreatureInfo[c_neu_rmb_id].level + 1;
   int c_neu_at = o_pCreatureInfo[c_neu_rmb_id].attack;
   int c_neu_df = o_pCreatureInfo[c_neu_rmb_id].defence;
   int c_neu_sp = o_pCreatureInfo[c_neu_rmb_id].speed;
   int c_neu_hp = o_pCreatureInfo[c_neu_rmb_id].hit_points;
   int c_neu_d1 = o_pCreatureInfo[c_neu_rmb_id].damage_min;
   int c_neu_d2 = o_pCreatureInfo[c_neu_rmb_id].damage_max;
   char* c_neu_ds = o_pCreatureInfo[c_neu_rmb_id].specification_description;

   sprintf(o_TextBuffer, "%s\n\nУровень: {%d}, Атака: {%d}, Защита: {%d},\nЗдоровье: {%d}, Урон: {%d}-{%d}, Скорость: {%d}.\n\n%s", o_TextBuffer, c_neu_lv, c_neu_at, c_neu_df, c_neu_hp, c_neu_d1, c_neu_d2, c_neu_sp, c_neu_ds);

   return EXEC_DEFAULT;
}

// bool apientry dllmain

         _PI->WriteLoHook(0x52FFEC, c_get_neu_rmb);
         _PI->WriteLoHook(0x530020, c_neu_rmb_public);
         _PI->WriteByte(0x530026, 120); // public y size
         _PI->WriteByte(0x53002D, 100); // public y pos
         _PI->WriteByte(0x530170, 217); // private y pos
Последний раз редактировалось Catastrophe 03 июн 2019, 07:30, всего редактировалось 7 раз(а).
Быстрее всего смогу ответить вам в Telegram: @PleaseAndThankYou
Вернуться к началу

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

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

Сообщение as239 » 02 июн 2019, 07:35

@RoseKavalier
Thanks a lot for help!

@AlexSpl
Хотел бы подкорректировать "Орлиный глаз" под сетевые нужды.
Срабатывать он должен после перехода хода в битве и давать шанс изучить заклинание, которое колдовалось противником в прошлом раунде.
Вы делали с Ben80 похожий мод. Но мне на хватает знаний чтобы его подкорректировать.
Вернуться к началу

offlineАватара пользователя
Catastrophe  
имя: Alex
Посвященный
Посвященный
 
Сообщения: 88
Зарегистрирован: 07 мар 2019, 11:50
Пол: Мужчина
Поблагодарили: 22 раз.

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

Сообщение Catastrophe » 02 июн 2019, 21:47

Подскажите, как можно создать сборный артефакт? Нашел в homm3.h следующее:
Код: Выделить всё
NOALIGN struct _Artifact_
{
 _int_ id;
 _int_ mod;
};

NOALIGN struct _ArtInfo_
{
 char* name;
 _int_ cost;
 _int_ position;
 _int_ type;
 char* description;
 _int_ supercomposite;
 _int_ part_of_supercomposite;
 _byte_ disabled;
 _byte_ new_spell;
 _byte_ field_1E;
 _byte_ field_1F;
};

Конкретно интересуют supercomposite и part_of_supercomposite. Как их можно использовать? И что такое mod в структуре артефакта?

Создал структуру для банков существ в homm3.h:
Код: Выделить всё
struct _CrBank_;
#define o_CrBank ((_CrBank_*)0x6702A0)

NOALIGN struct _CrBank_
{
   _dword_ slot1;
   _dword_ slot2;
   _dword_ slot3;
   _dword_ slot4;
   _dword_ slot5;
};

Использовать так: o_CrBank[от 0 до 10].slot1 = id существа;
Значение слота в 0xFFFFFFFF (-1) означает, что следующие слоты не учитываются.
Один из слотов ОБЯЗАН иметь значение 0xFFFFFFFF (-1), слоты после него - 0 (и кол-во в 0 в crtraits.txt)

id банков существ для массива:
  • 0 - склады циклопов
  • 1 - сокровищница гномов
  • 2 - консерватория грифонов
  • 3 - тайник бесов
  • 4 - кладовые медуз
  • 5 - нага банк
  • 6 - улей змиев
  • 7 - кораблекрушение
  • 8 - покинутый корабль
  • 9 - склеп
  • 10 - утопия драконов

 На примере склепа
Изображение

Код: Выделить всё
// elementals in crypt
o_CrBank[9].slot1 = 112; // air
o_CrBank[9].slot2 = 115; // water
o_CrBank[9].slot3 = 114; // fire
o_CrBank[9].slot4 = 113; // earth
o_CrBank[9].slot5 = 0xFFFFFFFF; // end of bank

Вся остальная инфа указывается в crbanks.txt, правда есть еще id существ, которых выдают в награду в банках, вот еще структура для них:
Код: Выделить всё
struct _CrBankReward_;
#define o_CrBankReward ((_CrBankReward_*)0x67037C)

NOALIGN struct _CrBankReward_
{
   _dword_ is_id;
};

Поскольку она состоит из одного единственного dword, ее, наверное, можно как-то проще записать, я сделал копипастом.
Использовать так: o_CrBankReward[от 0 до 10].is_id = id существ которых дают в награду;
 На примере того же склепа
Изображение

Код: Выделить всё
o_CrBankReward[9].is_id = 131;
Быстрее всего смогу ответить вам в Telegram: @PleaseAndThankYou
Вернуться к началу

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

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

Сообщение RoseKavalier » 03 июн 2019, 01:13

_Artifact_
mod is always -1, except spell scroll where it indicates ID of spell.

_ArtInfo_
It refers to the table in exe, I don't have the data off-hand. You can't really add more artifacts without moving the tables completely; some ERA mods do this (Amethyst? I forget).
From memory...
supercomposite is the id of the artifact that is a combination artifact (AoD, AA, PotDF, ...)
part_of_supercomposite is a boolean

_CrBank_
Similar, if you want more you need to move the table and its references.
The table you refer is probably derived from the stored data of CrBanks.txt.

Editing this stuff is easiest from Crbanks.txt itself, or a hook when the file is being read.
Adding more challenging, probably WoG has done it.
Вернуться к началу

offlineАватара пользователя
Catastrophe  
имя: Alex
Посвященный
Посвященный
 
Сообщения: 88
Зарегистрирован: 07 мар 2019, 11:50
Пол: Мужчина
Поблагодарили: 22 раз.

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

Сообщение Catastrophe » 03 июн 2019, 02:20

RoseKavalier писал(а):

You can't really add more artifacts without moving the tables completely

What about making artifacts combo ones? There are 3 unused arts in base game - diplomat's suit, mire of neutrality, ironfist of the ogre, how can I enable them?
Are you sure part_of_supercomposite is a boolean and not an id of combo art? I mean the recipe id, not id of an artifact itself, erm help indicates following combo art (recipe) ids:
0 Angelic Alliance
1 Cloak of the Undead King
2 Elixir of Life
3 Armor of the Damned
4 Statue of Legion
5 Power of the Dragon Father
6 Titan's Thunder
7 Admiral's Hat
8 Bow of the Sharpshooter
9 Wizard's Well
10 Ring of the Magi
11 Cornucopia
Быстрее всего смогу ответить вам в Telegram: @PleaseAndThankYou
Вернуться к началу

offlineАватара пользователя
Catastrophe  
имя: Alex
Посвященный
Посвященный
 
Сообщения: 88
Зарегистрирован: 07 мар 2019, 11:50
Пол: Мужчина
Поблагодарили: 22 раз.

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

Сообщение Catastrophe » 03 июн 2019, 04:58

ИИ всегда думает, как на максимальной сложности. Принцип работы: устанавливает сложность на 200% после выдачи ресурсов игрокам (by igrik) и возвращает изначально выбранную сложность при выставлении счета в таблицу рекордов (by me):
Код: Выделить всё
#include "homm3.h"

int c_chosen_difficulty;

_int_ __stdcall Hook_StartNewGame(LoHook* h, HookContext* c)
{
   c_chosen_difficulty = o_GameMgr->Field<_byte_>(0x1F6D8); // get initial difficulty
   o_GameMgr->Field<_byte_>(0x1F6D8) = 4; // set difficulty to 200%
   return EXEC_DEFAULT;
}

_int_ __stdcall c_score_calc1(LoHook* h, HookContext* c)
{
   c->ecx = c_chosen_difficulty; // return initial difficulty
   return EXEC_DEFAULT;
}

_int_ __stdcall c_score_calc2(LoHook* h, HookContext* c)
{
   c->eax = c_chosen_difficulty; // return initial difficulty
   return EXEC_DEFAULT;
}

// bool apientry dllmain

         _PI->WriteLoHook(0x4C0107, Hook_StartNewGame);
         _PI->WriteLoHook(0x4F46E2, c_score_calc1);
         _PI->WriteLoHook(0x4F4723, c_score_calc2);

При выставлении счета в таблицу рекордов сложность будет стоять "невозможно", но множитель к счету будет применен правильный, а название сложности в таблице рекордов не сохраняется. Я лично затер все упоминания сложности из ARRAYTXT.txt, поскольку в моем моде она влияет исключительно на количество ресурсов у игрока, кстати, по поводу ресурсов - кол-во стартовых ресурсов у компьютера на разных сложностях (от 80% до 200%, в оригинале там везде смешные цифры):
Код: Выделить всё
         _PI->WriteDword(0x6781FC, 30);
         _PI->WriteDword(0x678200, 15);
         _PI->WriteDword(0x678204, 30);
         _PI->WriteDword(0x678208, 15);
         _PI->WriteDword(0x67820C, 15);
         _PI->WriteDword(0x678210, 15);
         _PI->WriteDword(0x678214, 30000);
         
         _PI->WriteDword(0x678218, 30);
         _PI->WriteDword(0x67821C, 15);
         _PI->WriteDword(0x678220, 30);
         _PI->WriteDword(0x678224, 15);
         _PI->WriteDword(0x678228, 15);
         _PI->WriteDword(0x67822C, 15);
         _PI->WriteDword(0x678230, 30000);
         
         _PI->WriteDword(0x678234, 30);
         _PI->WriteDword(0x678238, 15);
         _PI->WriteDword(0x67823C, 30);
         _PI->WriteDword(0x678240, 15);
         _PI->WriteDword(0x678244, 15);
         _PI->WriteDword(0x678248, 15);
         _PI->WriteDword(0x67824C, 30000);
         
         _PI->WriteDword(0x678250, 30);
         _PI->WriteDword(0x678254, 15);
         _PI->WriteDword(0x678258, 30);
         _PI->WriteDword(0x67825C, 15);
         _PI->WriteDword(0x678260, 15);
         _PI->WriteDword(0x678264, 15);
         _PI->WriteDword(0x678268, 30000);
         
         _PI->WriteDword(0x67826C, 30);
         _PI->WriteDword(0x678270, 15);
         _PI->WriteDword(0x678274, 30);
         _PI->WriteDword(0x678278, 15);
         _PI->WriteDword(0x67827C, 15);
         _PI->WriteDword(0x678280, 15);
         _PI->WriteDword(0x678284, 30000);
Быстрее всего смогу ответить вам в Telegram: @PleaseAndThankYou
Вернуться к началу

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

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

Сообщение Ben80 » 03 июн 2019, 13:47

Все бы хорошо, но при загрузке или сохранении игры вы всегда будете видеть значок с королем (200%) вместо того, который изначально выбирали.
Вернуться к началу

offlineАватара пользователя
Catastrophe  
имя: Alex
Посвященный
Посвященный
 
Сообщения: 88
Зарегистрирован: 07 мар 2019, 11:50
Пол: Мужчина
Поблагодарили: 22 раз.

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

Сообщение Catastrophe » 03 июн 2019, 18:15

Ben80 писал(а):

Все бы хорошо, но при загрузке или сохранении игры вы всегда будете видеть значок с королем (200%) вместо того, который изначально выбирали.

Так все логично, сложность обратно не изменится до победы на карте. И значение c_chosen_difficulty не теряется при загрузке игры или даже перезапуска
Быстрее всего смогу ответить вам в Telegram: @PleaseAndThankYou
Вернуться к началу

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

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

Сообщение Ben80 » 03 июн 2019, 19:19

Не вижу тут логики. Раз вы выдаете игроку очки, соответствующие выбранной им сложности, а не 200%, значит, вы считаете, что он играет на выбранном уровне сложности. Значит при save/load и показывать ему надо выбранный уровень сложности.
Вернуться к началу

offlineАватара пользователя
Catastrophe  
имя: Alex
Посвященный
Посвященный
 
Сообщения: 88
Зарегистрирован: 07 мар 2019, 11:50
Пол: Мужчина
Поблагодарили: 22 раз.

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

Сообщение Catastrophe » 03 июн 2019, 22:30

Ben80 писал(а):

Раз вы выдаете игроку очки, соответствующие выбранной им сложности, а не 200%, значит, вы считаете, что он играет на выбранном уровне сложности.

Да вы правы конечно, я не спорю, как будет на это время, постараюсь исправить.

Делаю новые чит-коды. После Monty Python (RoE), Star Wars (AB), The Matrix (SoD) и Lord of the Rings (WoG) в моем моде будет... Back to the Future!
Решил немного поменять принцип, теперь сами коды интуитивны в написании (move, spell, puzzle, level, die), а отсылка к фильму будет в сообщении, отображающегося вместо "Мошенник!!!"
 
Изображение

Потребуется мой GENRLTXT.txt - https://drive.google.com/file/d/1DhjSCo ... sp=sharing
Метод отображения сообщений сделан крайне криво, КАЖДОЕ изменение GENRLTXT.txt заставит менять c_cheats_offset (благо, только его)

Если не брать мой GENRLTXT.txt (например, если у вас игра на английском), нужно проделать следующее:
1. С помощью txtedit добавить в GENRLTXT.txt новые строки и вписать в них сообщения, которые будут показываться при вводе чит-кода
2. С помощью notepad++ или подобной программы расчитать расстояние между началом строки с "Мошенник!!!" и началом строки с новым сообщением чит-кода
3. Полученное число подставить в c_cheats_offset и оффсеты к нему из c->esi из кода ниже
Код: Выделить всё
#include homm3.h

int c_code_id;

int c_cheats_offset = 20759;

int __stdcall c_code_message(LoHook* h, HookContext* c)
{
   switch (c_code_id)
   {
   case 1: c->esi += c_cheats_offset; break;
   case 2: c->esi += c_cheats_offset + 48; break;
   case 3: c->esi += c_cheats_offset + 129; break;
   case 4: c->esi += c_cheats_offset + 207; break;
   case 5: c->esi += c_cheats_offset + 261; break;
   case 6: c->esi += c_cheats_offset + 329; break;
   case 7: c->esi += c_cheats_offset + 431; break;
   case 8: c->esi += c_cheats_offset + 512; break;
   case 9: c->esi += c_cheats_offset + 553; break;
   case 10: c->esi += c_cheats_offset + 614; break;
   case 11: c->esi += c_cheats_offset + 720; break;
   case 12: c->esi += c_cheats_offset + 759; break;
   case 13: c->esi += c_cheats_offset + 819; break;
   default: c->esi += 0; break;
   }
   return EXEC_DEFAULT;
}

int __stdcall c_code_move(LoHook* h, HookContext* c)
{
   c_code_id = 1;
   return EXEC_DEFAULT;
}

int __stdcall c_code_hide(LoHook* h, HookContext* c)
{
   c_code_id = 2;
   return EXEC_DEFAULT;
}

int __stdcall c_code_show(LoHook* h, HookContext* c)
{
   c_code_id = 3;
   return EXEC_DEFAULT;
}

int __stdcall c_code_res(LoHook* h, HookContext* c)
{
   c_code_id = 4;
   return EXEC_DEFAULT;
}

int __stdcall c_code_build(LoHook* h, HookContext* c)
{
   c_code_id = 5;
   return EXEC_DEFAULT;
}

int __stdcall c_code_spell(LoHook* h, HookContext* c)
{
   c_code_id = 6;
   return EXEC_DEFAULT;
}

int __stdcall c_code_mech(LoHook* h, HookContext* c)
{
   c_code_id = 7;
   return EXEC_DEFAULT;
}

int __stdcall c_code_level(LoHook* h, HookContext* c)
{
   c_code_id = 8;
   return EXEC_DEFAULT;
}

int __stdcall c_code_morale(LoHook* h, HookContext* c)
{
   c_code_id = 9;
   return EXEC_DEFAULT;
}

int __stdcall c_code_luck(LoHook* h, HookContext* c)
{
   c_code_id = 10;
   return EXEC_DEFAULT;
}

int __stdcall c_code_puzzle(LoHook* h, HookContext* c)
{
   c_code_id = 11;
   return EXEC_DEFAULT;
}

int __stdcall c_code_die(LoHook* h, HookContext* c)
{
   c_code_id = 12;
   return EXEC_DEFAULT;
}

int __stdcall c_code_help(LoHook* h, HookContext* c)
{
   c_code_id = 13;
   return EXEC_DEFAULT;
}

// bool apientry dllmain

         _PI->WriteLoHook(0x402839, c_code_message);

         _PI->WriteHexPatch(0x63A4C8, "7A 62 69 72 00 00 00 00 00 00 00 00 00 00 00 00 00");
         _PI->WriteLoHook(0x402664, c_code_move);

         _PI->WriteHexPatch(0x63A508, "75 76 71 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
         _PI->WriteLoHook(0x40273B, c_code_hide);

         _PI->WriteHexPatch(0x63A4F4, "66 75 62 6A 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
         _PI->WriteLoHook(0x4026DD, c_code_show);

         _PI->WriteHexPatch(0x63A51C, "65 72 66 00 00 00 00 00 00 00 00 00 00 00 00");
         _PI->WriteLoHook(0x4027B8, c_code_res);

         _PI->WriteHexPatch(0x63A558, "6F 68 76 79 71 00 00");
         _PI->WriteLoHook(0x402933, c_code_build);

         _PI->WriteHexPatch(0x63A544, "66 63 72 79 79 00 00 00 00 00 00 00 00 00 00 00 00");
         _PI->WriteLoHook(0x4028CA, c_code_spell);

         _PI->WriteHexPatch(0x63A498, "7A 72 70 75 00 00 00 00 00 00 00 00 00");
         _PI->WriteLoHook(0x40254A, c_code_mech);

         _PI->WriteHexPatch(0x63A4A8, "79 72 69 72 79 00");
         _PI->WriteLoHook(0x4025E5, c_code_level);

         _PI->WriteHexPatch(0x63A4DC, "7A 62 65 6E 79 72 00 00 00 00 00");
         _PI->WriteLoHook(0x402685, c_code_morale);

         _PI->WriteHexPatch(0x63A4B0, "79 68 70 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
         _PI->WriteLoHook(0x40261B, c_code_luck);

         _PI->WriteHexPatch(0x63A4E8, "63 68 6D 6D 79 72 00 00 00");
         _PI->WriteLoHook(0x4026AC, c_code_puzzle);

         _PI->WriteHexPatch(0x63A48C, "71 76 72 00 00 00 00 00 00");
         _PI->WriteLoHook(0x402501, c_code_die);
         _PI->WriteByte(0x402514, 54); // 128+ is considered negative, so no phoenixes and azure dragons
         _PI->WriteByte(0x402512, 100); // same here

         _PI->WriteHexPatch(0x63A480, "75 72 79 63 00 00 00 00 00 00");
         _PI->WriteLoHook(0x4024BC, c_code_help);
         _PI->WriteByte(0x4024CF, 12); // same here
         _PI->WriteByte(0x4024CD, 100); // same here

         // disable nwcphisherprice
         _PI->WriteJmp(0x40295D, 0x402A1C);

Подскажите - как добавить в чит-код "move" каст Полёта на героя, помимо выдачи ему бесконечного передвижения?
Последний раз редактировалось Catastrophe 04 июн 2019, 07:27, всего редактировалось 2 раз(а).
Быстрее всего смогу ответить вам в Telegram: @PleaseAndThankYou
Вернуться к началу

Пред.След.

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

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

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