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


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

Улучшение ИИ

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

Re: Улучшение ИИ

Сообщение Rolex » 25 май 2021, 22:22

Ben80 писал(а):

то это конечно, совсем другой коленкор. Может, у них на сайте формула неправильно написана ?

На самом деле все правильно. Вот с другого источника:
Цитата:
Скорость любых существ под продвинутой и экспертной Медлительностью увеличена ровно на 1.

http://h3hota-aabb.ru/changelogsH3hota.html
https://h3hota.com/ru/documentation

Я все же думаю, что лучше будет сделать так, как у них. То есть заменить:
(Скорость + 1) / 2 на Скорость / 2 + 1

То есть получается, что в оригинале существа с непарным значением скорости теряют полединицы своей скорости после продвинутого/экспертного замедления.

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

Думаю, что Скорость / 2 + 1 будет более оптимальным решением, ибо в таком случае бонус к скорости получают, как существа с парным, так и непарным значением скорости.
Вернуться к началу

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

Re: Улучшение ИИ

Сообщение Ben80 » 26 май 2021, 02:32

Спасибо за инфу.

Rolex писал(а):


Думаю, что Скорость / 2 + 1 будет более оптимальным решением, ибо в таком случае бонус к скорости получают, как существа с парным, так и непарным значением скорости.


Сомнительно: хотовское решение не является более "справедливым" - по нему оказываются в выигрыше существа с четной скоростью, точно так же как в оригинале Тройки. Кроме того, появляется еще один существенный недостаток - для всей линейки медленных существ (до скорости 6 включительно) продвинутая/экспертная Медлительность действует так же, как базовая.
По видимому, идеального решения здесь попросту не существует, ну да ничего страшного.

Благодаря вам я понял возможный мотив создателей Тройки, округлявших эффект Медлительности вниз. Благодаря этому для любого существа Медлительность на продвинутом/экспертном уровне действует сильнее, чем на базовом уровне (если же округлять всегда вверх, то для каких-то медленных существ замедления скорости на базовом уровне не будет вовсе). Но эффект, как уже говорилось, получился абсолютно убойным, совсем не соответствующим заклинанию 1-го уровня.

***

Но я подумаю :smile1: Насчет того, чтобы рассмотреть хотовское решение и играть с ним. Если говорить об опоре на авторитет или традицию, при принятии моддерского решения, то, конечно, для меня гораздо большим авторитетом будет оригинальная Двойка, а не Хота.

***

Подумал, что лучшим решением будет применять двоечную формулу (Скорость + 1) * coef (с округлением вниз, coef равен 0.75 для базового уровня и 0.5 для продвинутого/экспертного) для любого уровня школы магии Земли. Так оно гораздо более системно, чем в первоначальном варианте, который я тут показал (а также более системно, чем хотовский вариант). Что получается:

Нач. скорость 3 4 5 6 7 8 9
Базов. медл. 3 3 4 5 6 6 7
Продв. медл. 2 2 3 3 4 4 5

Вроде бы кажется, что эффект получается маловат для базового уровня - но это вполне в русле Героев 3 (базовая Каменная кожа или Жажда крови - что, большой эффект что ли дают ?)

***

Оказывается, для мультипликатора скорости 0,75 (также как и для мультипликатора 0,5) для любой скорости округление итогового значения (после умножения) вверх - эквивалентно формуле (Скорость + 1) * coef (с дальнейшим округлением вниз).
Так что можно просто говорить о произведенных изменениях - "итоговая скорость округляется вверх, а не вниз", а формулу не поминать вовсе.
Вернуться к началу

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

Re: Улучшение ИИ

Сообщение Rolex » 26 май 2021, 09:16

Переделал немного ваш код. Сделал как в HotA:

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

using namespace std;

Patcher* _P;
PatcherInstance* _PI;

static _bool_ plugin_On = 0;

int __stdcall correctSlow_1(LoHook* h, HookContext* c)
{
   if (*(float*)(c->esi + 0x4C8) < 0.5001)
      c->eax = *(float*)(c->ebp - 8) * *(float*)(c->esi + 0x4C8) + 1;

   return EXEC_DEFAULT;
}

int __stdcall correctSlow_2(LoHook* h, HookContext* c)
{
   if (*(float*)(c->esi + 0x4C8) < 0.5001)
      c->eax = *(int*)(c->ebp - 4) * *(float*)(c->esi + 0x4C8) + 1;

   c->return_address += 0x14;
   return NO_EXEC_DEFAULT;
}

int __stdcall correctSlow_3(LoHook* h, HookContext* c)
{
   if (*(float*)(c->ecx + 0x4C8) < 0.5001)
      c->eax = *(float*)(c->ebp - 4) * *(float*)(c->ecx + 0x4C8) + 1;

   return EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
   if (DLL_PROCESS_ATTACH == ul_reason_for_call)
   {
      if (!plugin_On)
      {
         plugin_On = 1;
         _P = GetPatcher();
         _PI = _P->CreateInstance("HD.Plugin.CorrectSlow");

         // Продвинутая и экспертная Медлительность - округление вверх
         _PI->WriteLoHook(0x441D0A, correctSlow_1);
         _PI->WriteLoHook(0x441E2D, correctSlow_1);
         _PI->WriteLoHook(0x44858D, correctSlow_2);
         _PI->WriteLoHook(0x4485D5, correctSlow_2);
         _PI->WriteLoHook(0x448624, correctSlow_1);
         _PI->WriteLoHook(0x4486A2, correctSlow_1);
         _PI->WriteLoHook(0x448A2E, correctSlow_3);
      }
   }

   return TRUE;
}


Но возникло ряд вопросов по вашему коду.

1) Вот эта проверка
Код: Выделить всё
if (*(float*)(c->ecx + 0x4C8) < 0.5001)

нам нужна, я так понимаю для того, чтобы код работал только для продвинутого/экспертного замедления, так же?

2) Что делает
Код: Выделить всё
c->return_address += 0x14;

в correctSlow_2 и почему подобного нет в correctSlow_1 и correctSlow_3?

3) Порядок вызова лоухуков в данном случае нам важен или нет? Иными словами можем ли мы записать вот так:

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

         // Продвинутая и экспертная Медлительность - округление вверх
         _PI->WriteLoHook(0x441D0A, correctSlow_1);
         _PI->WriteLoHook(0x441E2D, correctSlow_1);
         _PI->WriteLoHook(0x448624, correctSlow_1);
         _PI->WriteLoHook(0x4486A2, correctSlow_1);
         _PI->WriteLoHook(0x44858D, correctSlow_2);
         _PI->WriteLoHook(0x4485D5, correctSlow_2);
         _PI->WriteLoHook(0x448A2E, correctSlow_3);


4) Зачем нам аж 7 лоухуков? Возможно ли решить поставленную задачу 1-2 лоухуками?
Последний раз редактировалось Rolex 26 май 2021, 13:30, всего редактировалось 2 раз(а).
Вернуться к началу

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

Re: Улучшение ИИ

Сообщение Ben80 » 26 май 2021, 09:44

Rolex писал(а):


Но возникло ряд вопросов по вашему коду.

1) Вот это проверка
Код: Выделить всё
if (*(float*)(c->ecx + 0x4C8) < 0.5001)

нам нужна, я так понимаю для того, чтобы код работал только для продвинутого/экспертного замедления, так же?



Да, конечно. На самом деле можно писать <= 0.5 (или даже == 0.5) вместо вычурного < 0.5001. Я просто побоялся иллюзорных фокусов с точностью float. Если бы кто-нибудь (например, AlexSpl) пошутил над этим и развеял страхи - я был бы только рад. Но никто не пошутил.

Rolex писал(а):

2) Что делает
Код: Выделить всё
c->return_address += 0x14;

в correctSlow_2 и почему подобного нет в correctSlow_1 и correctSlow_3?


Делает адресом возврата не адрес следующей инструкции (как бы это было по умолчанию), а адрес следующей инструкции + 20 (то есть 0x14). Почему нет подобного ? Потому что correctSlow_1 и correctSlow_3 выполняются в другом месте оригинального кода. Невозможно написать единый универсальный хук, который можно вставлять в любое место по своему желанию - везде нужно учитывать, какие оригинальные инструкции происходят до хука, и какие - после.

Rolex писал(а):

3) Порядок вызова лоухуков в данном случае нам важен или нет? Иными словами можем ли мы записать вот так:


Порядок не важен и записать так можем.

Rolex писал(а):

4) Зачем нам аж 7 лоухуков? Возможно ли решить поставленную задачу 1-2 лоухуками?


Вряд ли можно решать эту задачу 1-2 лоухуками. Почему 7 ? - потому что столько раз происходит расчет скорости в оригинальном коде с учетом мультипликатора. Мы же не можем где-то внедрить изменение, а где-то махнуть рукой.

***

На самом деле 7 лохуков - из-за недостатков оригинального кода. Там есть универсальная функция GetSpeed для боя, где происходит расчет. Туда лохук я поставил. Но в оригинальном коде есть несколько случаев, когда вместо вызова этой функции производится "самостоятельный" расчет (хотя, видимо, можно было бы просто вызвать эту функцию).
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5540
Зарегистрирован: 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)
Поблагодарили: 2155 раз.

Re: Улучшение ИИ

Сообщение AlexSpl » 26 май 2021, 14:12

Сравнивать числа с плавающей точкой можно и без эпсилона, но с оговорками. Левая часть - *(float*)(c->ecx + 0x4C8) - очевидно не есть результат вычислений (нет накопления погрешностей), а 0.5 - красивое число, которое целиком помещается в 4 байта (т.е. 0.5f = 0.5). Но если мы сравниваем результат вычислений с фиксированным значением, которое не помещается в 4 байта (8 - для double), т.е. усекается, то эпсилон обязателен.
Вернуться к началу

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

Re: Улучшение ИИ

Сообщение Ben80 » 29 май 2021, 11:56

Нашел решение, как в битвах-симуляциях учесть стрелковые башни. При этом используется кастомная глобальная структурка, в которую позже можно будет добавить и заклинания, выученные в битве посредством Орлоглаза (в оригинале это не учитывается). Но пока с Орлоглазом заморачиваться не буду.

***

Поскольку стрелковые башни игнорируют защиту цели, то при желании можно ввести модификатор, линейно зависящий от средней силы существ averagePower = armyStrength / nCreatures

Код: Выделить всё
int __stdcall fix_AI_SimulationBattle_ArrowTowers(LoHook* h, HookContext* c)
{
   _AI_SimulationBattle_Side_* battleSide = (_AI_SimulationBattle_Side_*)c->ecx;
   if(!battleSide->isRestrictedMovement)
   {
      if(simBattleAux.nTurrets == 1)
      {
         c->ebx = 80 * simBattleAux.nBuildings;
      }
      if(simBattleAux.nTurrets == 3)
      {
         c->ebx = 80 * (2 * simBattleAux.nBuildings + 1);
      }
   }

   return EXEC_DEFAULT;
}

...

_PI->WriteLoHook(0x42639F, fix_AI_SimulationBattle_ArrowTowers);
Последний раз редактировалось Ben80 04 июн 2021, 07:35, всего редактировалось 1 раз.
Вернуться к началу

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

Re: Улучшение ИИ

Сообщение as239 » 02 июн 2021, 07:59

На HW igrik написал про следующие ошибки:
1. ошибка в начислении опыта выигравшим героем ИИ (нет +500 опыта за побежденного героя)
2. нет передачи артефактов выигравшему герою
3. все артефакты остаются у поверженного.
4. ошибка, связанная с бонусами Альянса Ангелов в битве против нейтралов
5. ИИ герой может сбежать в битве даже при Оковах Войны- при переполнении просчёта, герою ИИ может добавляться армия в миллионах!! существ после битвы.
6. герой с огромнейшей армией проигрывает малой численности нейтралов.

Было бы полезно иметь плагин(ы) исправляющие их.
Вернуться к началу

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

Re: Улучшение ИИ

Сообщение Ben80 » 02 июн 2021, 08:27

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

Я HD мод не использую, поэтому для меня моменты, перечисленные выше, имеют значение.

п.2-3 - это я исправлял (можно найти в теме ASI плагинов для Героев 3), RoseKavalier также знает исправление
п.4 - пока не могу ничего сказать. Вообще, в битвы-симуляции нужно добавлять/отнимать бонусы, связанные с моралью и удачей (естественно, не через сами показатели морали и удачи), учитывать влияние суперартефактов, влияние Плаща Отречения (сейчас учитывается только Сфера Запрещения) и тд. + Бонусы, связанные с навыками Доспехи и Нападение у героев.
по поводу переполнения (не только в битвах-симуляциях, но и в других моментах игры) - никогда не считал это за реальную проблему, так как нужно умудриться собирать такие армии или набирать героями такие показатели, чтобы происходило переполнение. Редко кто любит и играет в такого рода игры.

Для Оков войны добавочный код не сложен:
Код: Выделить всё
int __stdcall AI_checkShacklesOfWar(LoHook* h, HookContext* c)
{
   _Hero_* hero1 = (_Hero_*)(c->eax);
   _Hero_* hero2 = (_Hero_*)(c->ebx);

   if(hero1->DoesWearArtifact(AID_SHACKLES_OF_WAR) || hero2->DoesWearArtifact(AID_SHACKLES_OF_WAR))
   {
      c->return_address = 0x426F50;
      return NO_EXEC_DEFAULT;
   }

    return EXEC_DEFAULT;
}
...
_PI->WriteLoHook(0x426F33, AI_checkShacklesOfWar);
Вернуться к началу

offlineАватара пользователя
leiz  
Подмастерье
Подмастерье
 
Сообщения: 185
Зарегистрирован: 15 сен 2018, 07:58
Пол: Не указан
Поблагодарили: 95 раз.

Re: Улучшение ИИ

Сообщение leiz » 02 июн 2021, 09:27

Цитата:
6. герой с огромнейшей армией проигрывает малой численности нейтралов.

Неужели та же ошибка, которая с Единички тянется? AlexSpl ее подробно разобрал в свое время.
Вернуться к началу

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

Re: Улучшение ИИ

Сообщение Ben80 » 02 июн 2021, 09:31

leiz писал(а):

Неужели та же ошибка, которая с Единички тянется? AlexSpl ее подробно разобрал в свое время.


Суть любого переполнения одинакова - число не помещается в отведенные под него байты.
Вернуться к началу

Пред.След.

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

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

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

cron