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


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

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

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

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

Сообщение Rolex » 18 мар 2021, 00:12

AlexSpl писал(а):

Насчёт выбора целей. Вы можете выполнять Ваш алгоритм в теле функции ResetMagicMirrorFlags(). А в getEnemyStackToRedirectTo() просто "снимать" верхний в стеке/массиве отряд. В случае массива Вам придётся завести глобальную переменную, которую нужно будет инкрементировать при каждом выборе цели. Также нужно учесть случай, когда перенаправлять некуда:

Так и сделал, вроде, все работает.

AlexSpl писал(а):

По алгоритму. Вы заполняете и сортируете массив указателей на отряды (_BattleStack_*) в ResetMagicMirrorFlags(). Можно, кстати, сразу переименовать функцию в какой-нибудь dataInit(). Далее, устанавливаете индекс (пусть будет iStack), который будет выбирать отряд из этого массива, в 0. В getEnemyStackToRedirectTo() Вы возвращаете указатель на отряд с индексом iStack, инкрементируя индекс. Если не хотите работать с указателями, можно так:

Код: Выделить всё
return &o_BattleMgr->stack[1 - o_BattleMgr->current_side][combatPowerOfStacks[position++].second];


Должно работать. Да, и не забудьте про контроль индекса массива. Если следующий индекс выходит за границы, возвращайте 0 (соответствует случаю, когда заклинание отражается "в пустоту").

Так не работает. Вот так работает:
Код: Выделить всё
return &o_BattleMgr->stack[1 - stack->side][combatPowerOfStacks[stackIndex++].second];

То есть вместо o_BattleMgr->current_side вот это: stack->side.

Вот такой код этих двух функций у меня получился:

Код: Выделить всё
_BattleStack_* getEnemyStackToRedirectTo(_BattleStack_* stack, int spell)
{
   if (stackIndex == combatPowerOfStacks.size()) return NULL; else
      return &o_BattleMgr->stack[1 - stack->side][combatPowerOfStacks[stackIndex++].second];
}

int __stdcall dataInit(LoHook* h, HookContext* c)
{
   showMagicMirrorAnim = false;
   showMagicResistAnim = false;
   memset(needMagicMirrorAnim, false, 40);
   memset(needMagicResistAnim, false, 40);

   combatPowerOfStacks.resize(o_BattleMgr->stacks_count[o_BattleMgr->current_side]);

   for (int i = 0; i < combatPowerOfStacks.size(); ++i)
   {
      _BattleStack_* stack = &o_BattleMgr->stack[o_BattleMgr->current_side][i];
      combatPowerOfStacks[i].first = o_pCreatureInfo[stack->creature_id].fight_value * stack->count_current;
      combatPowerOfStacks[i].second = i;
   }

   sort(combatPowerOfStacks.begin(), combatPowerOfStacks.end(), my_cmp);

   stackIndex = 0;

   return EXEC_DEFAULT;
}



Я в своей функции хочу доработать проверку выбора одиночной цели. Но что-то не выходит.

Взял из reflectSpell() это:

Код: Выделить всё
   int spell = *(int*)(c->ebp + 0xC);
   int spellPower = *(int*)(c->ebp + 0x14);
   int schoolLevel = *(int*)(c->ebp + 0x10);
   _Hero_* hero = *(_Hero_**)(c->ebp + 8);


В общем если выбранная цель является Золотым драконом, а уровень отраженного закла в пределах 1-4 уровня, то игнорим Золотых драконов как цель и переходим к следующему по силе отряду (если он есть), иначе (если закл 5-го уровня) оставляем их в качестве цели.

Пытался вот так, но не работает:
Код: Выделить всё
stack->creature_id == CID_GOLD_DRAGON && schoolLevel <= 3
stack->creature_id == CID_GOLD_DRAGON && o_Spell[spell].level <= 3


По Антимагии, если среди наложенных заклов есть Антимагия, то сравниваем уровень отраженного закла с уровнем Антимагии. Если уровень отраженного закла менее или равен тому уровню, который может блокировать наложенная Антимагия, то игнорим данных монстров как цель и переходим к следующему по силе отряду (если он есть), иначе оставляем их в качестве цели.

Ничего из нижеперечиленного не заработало правильно:
Код: Выделить всё
stack->active_spell_duration[SPL_ANTI_MAGIC] && schoolLevel <= *(int*)o_Spell[SPL_ANTI_MAGIC].effect + 1
stack->active_spell_duration[SPL_ANTI_MAGIC] && o_Spell[spell].level <= *(int*)o_Spell[SPL_ANTI_MAGIC].effect + 1
stack->active_spell_duration[SPL_ANTI_MAGIC] && o_Spell[spell].level <= hero->spell_level[SPL_ANTI_MAGIC] + 1


Потом эти же проверки мне нужно будет закинуть в dataInit() или getEnemyStackToRedirectTo(). И вот здесь даже и не знаю как лучше поступить, так как здесь цель уже не одна. Придется заводить, наверное, еще один массив/стек. Просто если мы какие-то отряды из-за проверки пропустим, то потом возможно придется к ним вернутся. Например, если те отряды, которые выбирались до этого погибли или изначально других отрядов не было, а те, которые не прошли проверку мы пропустили или на отряде закончилось действие Антимагии. В общем здесь сложнее... Даже и не знаю как здесь сделать нормально.

Без ShouldNotRenderBattle() по окончанию быстрой битвы звук исчезает. Но ShouldNotRenderBattle() не определен. А как это исправить?


**************************************************************************************************************************
Я вот сейчас подумал над отражением площадных спеллов.
Вы писали:
AlexSpl писал(а):

Площадные заклинания мы, как я понял из FizMiG, не отражаем, ибо иначе всё было бы очень сложно: кастанули Inferno на три отряда под Magic Mirror, а в ответ получили три каста Inferno


Но таже Антимагия - закл 3-го уровня, игнорит площадные заклы. Так почему же закл 5-го уровня не может их отражать? Да, в оригинале он не отражает, но мы же его усиливаем. Так вот у меня идея такая: а что если не отражать для каждого отряда свой Инферно, например, а сделать наоборот, один Инферно накладывается на то кол-во вражексих отрядов, которые отразили его.

Поясню:
Например, кастуем мы Инферно (или Метеоритный дождь) на 3 вражексих отряда под Зеркалом. 2 из 3 отражает его. Значит для 2 мы проигрываем анимацию Зеркала и игнорим урон, а для 3-го ничего не делаем, он получает урон, так как не отразил его (аналогично отряду без Зеркала).
После чего, исходя из площади, которую может охватить данный закл, мы ищем на поле боя место скопление моих отрядов и разворачиваем его в том месте и таким образом, чтобы он захватил именно то кол-во отрядов, которые отразили его.
Если же развернуть этот площадный закл мы можем на то кол-во отрядов, которые отразили его, несколькими способами, то выбираем такой вариант, где суммарная сила отрядов на которые мы можем развернуть его - максимальная.
Если же мы не можем развернуть его на то кол-во, которое его отразило, тогда просто выбираем максимально возможное на которое можем развернуть.

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

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 » 18 мар 2021, 05:34

Цитата:
Я в своей функции хочу доработать проверку выбора одиночной цели. Но что-то не выходит.

Вы должны понимать, что stack в reflectSpell() - это стек, который отражает заклинание, а stackFoe - это стек, на который заклинание отражается; schoolLevel - это уровень развития школы магии или эффективный уровень: например, 3 (Эксперт) на магических полях.

Цитата:
Но ShouldNotRenderBattle() не определен. А как это исправить?

В смысле не определён?

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

Тут не нужно волноваться. Функция dataInit() вызывается перед каждым масскастом.
Вернуться к началу

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

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

Сообщение Rolex » 18 мар 2021, 10:06

AlexSpl писал(а):

schoolLevel - это уровень развития школы магии или эффективный уровень: например, 3 (Эксперт) на магических полях.


Я почему-то подумал, что за это у вас отвечает spellPower. Попутал значит. Но мне нужен как раз уровень закла к которому он относится в Гильдии магов (1-5 уровень). Это я так понимаю у вас тогда spellPower? Если нет, тогда как его можно получить? Вот так по идее должно работать o_Spell[spell].level, если конечно spell - это ID закла у вас. Но не работает. spellPower у вас будет эквивалентно o_Spell[spell].level ?
AlexSpl писал(а):

В смысле не определён?

Не компилируется с ним.
Вернуться к началу

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 » 18 мар 2021, 12:27

Да, точно. Метод ShouldNotRenderBattle() является методом менеджера битвы:

Код: Выделить всё
int __stdcall skipOrigSound(LoHook* h, HookContext* c)
{
    // Отключаем оригинальный звук, если это масскаст, тип 0x11, или битва невидима (по умолчанию)
    if ( !c->edi && ((char*)0x5A2B48)[*(int*)(c->ebp + 8) - 0xA] == 0x11 || o_BattleMgr->ShouldNotRenderBattle() )
    {
        c->return_address = 0x5A0646;
        return NO_EXEC_DEFAULT;
    }
   
    return EXEC_DEFAULT;
}


Цитата:
Вот так по идее должно работать o_Spell[spell].level, если конечно spell - это ID закла у вас. Но не работает.

Да, так и нужно получать уровень кастуемого заклинания, но только в функции reflectSpell(). А Вам где ID спелла нужно получить?
Вернуться к началу

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

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

Сообщение Rolex » 18 мар 2021, 12:34

AlexSpl писал(а):

Да, так и нужно получать уровень кастуемого заклинания, но только в функции reflectSpell(). А Вам где ID спелла нужно получить?

В своей функции NewTarget, где выбирается одиночная цель. Для начала там сделать нужно:

Код: Выделить всё
int __stdcall NewTarget(LoHook* h, HookContext* c)
{
   int pos = 0;
   int spell = *(int*)(c->ebp + 0xC);

   combatPowerOfStacks.resize(o_BattleMgr->stacks_count[o_BattleMgr->current_side]);

   for (int i = 0; i < combatPowerOfStacks.size(); ++i)
   {
      _BattleStack_* stack = &o_BattleMgr->stack[o_BattleMgr->current_side][i];
      combatPowerOfStacks[i].first = o_pCreatureInfo[stack->creature_id].fight_value * stack->count_current;
      combatPowerOfStacks[i].second = i;
   }

   sort(combatPowerOfStacks.begin(), combatPowerOfStacks.end(), my_cmp);

   for (int i = 0; i < combatPowerOfStacks.size(); ++i)
   {
      _BattleStack_* stack = &o_BattleMgr->stack[o_BattleMgr->current_side][combatPowerOfStacks[i].second];
      
      if (stack->creature_id == CID_BLACK_DRAGON || stack->creature_id == CID_MAGIC_ELEMENTAL || stack->creature_id == CID_GOLD_DRAGON && o_Spell[spell].level <= 3) continue; else
      {
         pos = combatPowerOfStacks[i].second;
         break;
      }
   }
   
   c->eax = (int)&o_BattleMgr->stack[o_BattleMgr->current_side][pos];

   return EXEC_DEFAULT;
}


То есть нужно, чтобы все заклы до 4-го уровня перенапрвлялись на второй по силе отряд после Золотого дракона, а если направляемый закл 5-го уровня, то уже на Золотого.
Почему вот это не работает?
Код: Выделить всё
stack->creature_id == CID_GOLD_DRAGON && o_Spell[spell].level <= 3
Вернуться к началу

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 » 18 мар 2021, 12:42

Давайте немножко поясню. Запись вида *(int*)(c->ebp + 0xABC); означает, что перед Вами аргумент типа int, переданный конкретной функции, и в других функциях это работать не будет. Есть ещё то же самое, но с минусом: *(int*)(c->ebp - 0xABC); Это - локальная переменная (тип int) функции. Разумеется, в других функциях это тоже работать не будет. Судя по заголовку, у Вас NewTarget() - LoHook? Но я не вижу адреса. Если это Ваша кастомная функция, то заголовок должен быть таким: int NewTarget(int spell); и вызывать эту функцию Вы должны так: NewTarget(spell), где в качестве аргумента передаётся ID спелла.

Так, вижу, что это LoHook :smile1: Подскажите адрес, и я скажу, как получить spell.
Вернуться к началу

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

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

Сообщение Rolex » 18 мар 2021, 12:58

Вы же сами мне этот адрес давали. :smile1:
_PI->WriteLoHook(0x5A05CC, NewTarget);
Вернуться к началу

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 » 18 мар 2021, 13:09

int spell = *(int*)(c->ebp + 8); // 8 - это первый аргумент, передающийся через стек
Вернуться к началу

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

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

Сообщение Rolex » 18 мар 2021, 13:14

Спасибо. И еще вопрос. Как в этой же функции получить уровень развития школы магии (эффективный уровень) наложенного на отряд заклинания Антимагия, так *(int*)o_Spell[SPL_ANTI_MAGIC].effect ?
Вернуться к началу

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 » 18 мар 2021, 13:18

Правильно получать так: int effSchoolLevel = CALL_3(int, __thiscall, 0x4E52F0, hero, SPL_ANTI_MAGIC, o_BattleMgr->spec_terr_type); но нужен указатель на героя. Догадаетесь, как его получить? :smile2: А effect - это то, что Вы видите в sptraits.txt (обычно в процентах), т.е. величины на протяжении игры неизменные.
Вернуться к началу

Пред.След.

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

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

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