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


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

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

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1318
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

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

Сообщение Ben80 » 02 сен 2017, 14:55

Кстати, Зыбучих песков и Мин не нашел в 00444610 combatMonster_ApplySpell

И вообще с трудом там разобрался, какой участок кода к какому заклинанию относится.
Лично Вы как с этой проблемой справились ?

Свич идет по некоему числу, загруженному в ECX:
004446E5 lea ecx, [ebx-1Bh]

Что это за число вообще ? Оно не совпадает с обычным ID заклинания.
Вернуться к началу

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

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

Сообщение Ben80 » 02 сен 2017, 15:00

igrik на df2, кстати, написал, где, по его мнению стоит копать по TownPortal:
http://forum.df2.ru/index.php?showtopic ... ntry744194

Посмотрел, пока не вижу как это можно использовать.

Похоже, он не прав, но инфа полезная, 200 и 300 тут тоже надо подправить.
Вот Си код участка, о котором говорил igrik:
Код: Выделить всё
JumpHero((void *)pAdvManager, (_Hero_ *)v6, *(_DWORD *)v16, 0, 1, 0);
      v55 = GetTypeOfLandModifierUnderHero((_Hero_ *)v6);
      v56 = CalcSpellCost4Hero((char *)v6, 9, 0, v55);
      sub_004D9540((_Hero_ *)v6, v56);
      v57 = GetTypeOfLandModifierUnderHero((_Hero_ *)v6);
      v58 = *(_DWORD *)(v6 + 77) - (Hero_GetSchoolLevelOfSpell((_Hero_ *)v6, 9, v57) != 3 ? 300 : 200);
      *(_DWORD *)(v6 + 77) = v58;
      if ( (signed int)v58 < 0 )
        *(_DWORD *)(v6 + 77) = 0;
Вернуться к началу

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

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

Сообщение Ben80 » 02 сен 2017, 16:17

Анализирую
//----- (0041D4E0) --------------------------------------------------------
char __thiscall Cast_TownPortal(int this, signed int a2)

Может, для компа не срабатывает моя поправка, только для игрока ?
Последний раз редактировалось Ben80 02 сен 2017, 17:01, всего редактировалось 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: Как создать плагин для HD мода

Сообщение AlexSpl » 02 сен 2017, 16:38

Цитата:
Потестировал свой плагин для Городского портала. Комп не использует эту возможность при основном уровне Магии Земли.


Какую возможность? Перемещаться в любой замок?
Вернуться к началу

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

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

Сообщение Ben80 » 02 сен 2017, 17:00

Да, перемещаться в любой замок.

На тестовой карте мой Герой околачивается рядом с замком компа и если у компа есть Земля выше основной, он туда телепортируется, защищает его.
Вернуться к началу

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 » 02 сен 2017, 20:45

Посмотрите условный переход по адресу 56B3B4h. Далее, для порядка стоимость заклинания в MP нужно также изменить по адресам 56B5AAh и 430532h (LoHook, стоимость в eax).

Два эквивалентных патча:

Код: Выделить всё
_PI->WriteHexPatch(0x56B3B4, "90 90 90 90 90 90");


Код: Выделить всё
_PI->WriteHexPatch(0x56B3B4, "EB 04");


Цитата:
И вообще с трудом там разобрался, какой участок кода к какому заклинанию относится.
Лично Вы как с этой проблемой справились ?

Свич идет по некоему числу, загруженному в ECX:
004446E5 lea ecx, [ebx-1Bh]

Что это за число вообще ? Оно не совпадает с обычным ID заклинания.


 
1Bh = 27 - ID первого заклинания, у которого есть длительность: раунд/сила магии (Shield). Если посмотрите таблицу индексов для этого свитча по адресу 445178, то увидите там много одинаковых байтов (20h), соответствующих индексу по умолчанию (default):

Код: Выделить всё
.text:00445178                 db      4,     5,     6,     7                   ; indirect table for switch statement
.text:00445178                 db    20h,     8,   20h,   20h
.text:00445178                 db    20h,   20h,     9,   0Ah
.text:00445178                 db    0Bh,   0Ch,   0Dh,   0Eh
.text:00445178                 db    20h,   0Fh,   10h,   11h
.text:00445178                 db    12h,   13h,   14h,   15h
.text:00445178                 db    16h,   17h,   20h,   18h
.text:00445178                 db    19h,   1Ah,   1Bh,   1Ch
.text:00445178                 db    20h,   20h,   20h,   20h
.text:00445178                 db    20h,   20h,   20h,   20h
.text:00445178                 db    1Dh,   20h,   1Eh,   20h
.text:00445178                 db    1Fh


В начале этой таблицы (до 4-ки) должно было быть ещё 27 (1Bh) таких индексов (20h), соответствующих заклинаниям с номерами 0 - 26. И код выглядел бы так:

Код: Выделить всё
lea ecx, [ebx]


Либо ID заклинания (ebx) напрямую выступало бы индексом (lea ecx, [ebx] <=> mov ecx, ebx).

Но компилятор оптимизирует код, в том числе его размер. Поэтому первые 27 одинаковых индексов он из таблицы выкинул и заменил команду на

Код: Выделить всё
lea ecx, [ebx-27]
Вернуться к началу

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

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

Сообщение Ben80 » 02 сен 2017, 22:04

Может быть, я бы сам и нашел эту функцию, но меня подвело стремление использовать Си код, а там вот что оказалось:
//----- (0056B320) --------------------------------------------------------
#error "FFFFFFFF: function frame is wrong (funcsize=0)"

Редкий случай.

Соответственно, мой поиск по сишному файлу "Hero_GetSchoolLevelOfSpell" эту функцию (0056B320) не выдал.
Вернуться к началу

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 » 02 сен 2017, 22:13

Это, скорее всего, проблема воговской базы. У меня эта функция декомпилируется без проблем.
Вернуться к началу

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

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

Сообщение Ben80 » 03 сен 2017, 07:17

Тогда финальный(?) код для Городского портала будет такой, если не возражаете:

Код: Выделить всё

#include "..\..\include\homm3.h"

// объекты patcher_x86.
Patcher* _P;
PatcherInstance* _PI;

int __stdcall skipTownPortalConfirm(LoHook* h, HookContext* c)
{
   if ( c->eax == -1 ) {
      c->ecx = *(char*)(c->edi + 5); // Выполняем затёртую jmp-патчем команду
      c->return_address = 0x41D990; // Обходим jmp-патч
      return NO_EXEC_DEFAULT;
   }
   
   c->return_address = 0x41D939;
   return NO_EXEC_DEFAULT;
}

int __stdcall advancedEarth(LoHook* h, HookContext* c) {
   c->eax = 1000;
   return EXEC_DEFAULT;
}

int __stdcall mpointsEarth_1(LoHook* h, HookContext* c) {
   int level = c->eax;
   int mpoints[] = {1200, 1200, 1000, 800};
   c->eax = mpoints[level];
   
   c->return_address = 0x56B5AA;
   return NO_EXEC_DEFAULT;
}

int __stdcall mpointsEarth_2(LoHook* h, HookContext* c) {
   int level = c->eax;
   int mpoints[] = {1200, 1200, 1000, 800};
   c->eax = mpoints[level];
   
   c->return_address = 0x430532;
   return NO_EXEC_DEFAULT;
}

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
static _bool_ plugin_On = 0;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (!plugin_On)
{
plugin_On = 1;

_P = GetPatcher();
_PI = _P->CreateInstance("HD.Plugin.TownPortal");



_PI->WriteHexPatch(0x41D534, "20 03"); // меняем расходы MP на экспертном уровне Магии, с 200 на 800
_PI->WriteHexPatch(0x41D51F, "B0 04"); // меняем расходы MP на основном уровне Магии, с 300 на 1200
_PI->WriteHexPatch(0x41D6D1, "90 90 90 90 90 90 90 90 90 90"); // отменяем проверку на уровень Магии Земли в главной функции заклинания
_PI->WriteLoHook(0x41D52E, advancedEarth); // расходы MP в главной функции заклинания - для продвин. уровня - 1000
_PI->WriteLoHook(0x56B59B, mpointsEarth_1); // расходы MP во вспомогат. функции 1
_PI->WriteHexPatch(0x56B3B4, "90 90 90 90 90 90"); // отменяем проверку на уровень Магии Земли во вспомогат. функции 1
_PI->WriteLoHook(0x430520, mpointsEarth_2); // расходы MP во вспомогат. функции 2
_PI->WriteLoHook(0x41D934, skipTownPortalConfirm); // обходим jmp патч HD мода (версии 3.809 и выше)
}
break;

case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}



Если Вы не против, разместим это в публичном доступе (на df2) за совместным соавторством.
А почему, кстати, "c->edi + 5" ? В IDA там вот что - "0041D98B movzx cx, [edi+_TownSetup_.x]"
Вернуться к началу

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

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

Сообщение Ben80 » 03 сен 2017, 13:40

По заклинанию Disguise пока написал очень забавный плагин, преувеличивающий численность отрядов в 5 раз, если было наложено заклинание (любого уровня). Забавен он тем, что автор по сути уклонился от разбора кода оригинальной игры.
Хотя тут возможны проблемы. Что будет, если например, играют 3 игрока, один игрок не в свой ход рассматривает вражеского героя правой кнопкой, и тут на этого героя нападает третий игрок, у которого сейчас ход ?
Разве что запретить такой просмотр (просмотр героев, а не монстров на карте) не в свой ход ?

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

Patcher* _P;
PatcherInstance* _PI;

int __stdcall maskSpell_start(LoHook* h, HookContext* c)
{
   int hero = *(int*)(c->ebp + 8);
   if(*(int*)(hero + 270)>-1)
   {
      *(int*)(hero + 145 + 7*4) *= 5;
      *(int*)(hero + 145 + 7*4 + 4) *= 5;
      *(int*)(hero + 145 + 7*4 + 8) *= 5;
      *(int*)(hero + 145 + 7*4 + 12) *= 5;
      *(int*)(hero + 145 + 7*4 + 16) *= 5;
      *(int*)(hero + 145 + 7*4 + 20) *= 5;
      *(int*)(hero + 145 + 7*4 + 24) *= 5;
   }

   return EXEC_DEFAULT;
}

int __stdcall maskSpell_end(LoHook* h, HookContext* c)
{
   int hero = *(int*)(c->ebp + 8);
   if(*(int*)(hero + 270)>-1)
   {
      *(int*)(hero + 145 + 7*4) /= 5;
      *(int*)(hero + 145 + 7*4 + 4) /= 5;
      *(int*)(hero + 145 + 7*4 + 8) /= 5;
      *(int*)(hero + 145 + 7*4 + 12) /= 5;
      *(int*)(hero + 145 + 7*4 + 16) /= 5;
      *(int*)(hero + 145 + 7*4 + 20) /= 5;
      *(int*)(hero + 145 + 7*4 + 24) /= 5;
   }

   return EXEC_DEFAULT;
}

int __stdcall maskSpell_middle(LoHook* h, HookContext* c)
{
   c->eax = -1;
   return EXEC_DEFAULT;
}


BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
static _bool_ plugin_On = 0;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (!plugin_On)
{
plugin_On = 1;

_P = GetPatcher();
_PI = _P->CreateInstance("HD.Plugin.Disguise");

_PI->WriteLoHook(0x52F0C1, maskSpell_start);
_PI->WriteLoHook(0x52F874, maskSpell_end);
_PI->WriteLoHook(0x52F461, maskSpell_middle);

}
break;

case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

Вернуться к началу

Пред.След.

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

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

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