Объявления

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

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

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

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

Сообщение Rolex » 07 апр 2021, 12:26

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

Логика такая:
Код: Выделить всё
// Заводим вектор:
vector <pair<double, int>> target;
int bestTarget;

// Как и в случае с площадными берем минимум в кол-ве возможно убитых существ и текущем кол-ве и умножаем на его fight_value одного существа. В некоторых случаях кол-во самых сильных существ может быть гораздо меньше чем тот урон который может нанести закл. А в таком случае после сортировки этот отряд вряд ли будет самым сильным.

// Ибо в армии героя могут быть чуть менее слабые существа, но в большем кол-ве, которые смогут принять весь урон закла. Следовательно кол-во убитых таких существ может быть сильнее чем гораздо меньшее кол-во более сильных, где большая часть урона ушла в пустую.

target[i].first = ( min( (double)spellDemage / stack->full_hp ), stack->count_current ) * o_pCreatureInfo[stack->creature_id].fight_value;
target[i].second = i;

// Сортим по убыванию target[i].first с сохранением индексов.
// То есть после сортировки в target[0].second у нас будет хранится индекс самого сильного существа на поле боя (от 0 до 9), target[1].second второго по силе и тд.

for (int i = 0; i < target.size(); ++i)
{
   _BattleStack_* stack = &o_BattleMgr->stack[o_BattleMgr->current_side][ target[i].second ];
   
   // если урон от нашего дамажащего закла разделенный на остаток здоровья проверяемого существа более или равен единице, то выбираем стек с индексом target[i].second - наша цель.
   if ( (double)spellDemage / (stack->full_hp - stack->lost_hp) >= 1.0 )
   {
      bestTarget = target[i].second
      break;
   }
}

На мой взгяд такой алгоритм найболее оптимален.

Пример:
У нас есть 3 отряда: 2 Архангела, 4 Чемпиона и 100 Королевских Грифонов. Самый сильный из перечисленных с учетом кол-ва - это Грифоны.
Тот алгоритм, который у нас есть сейчас будет отдавать приоритет именно Грифонам. А тот, который у площадных, при уроне не более 500 ед, будет отдавать приоритет Архангелам. И с точки зрения снижения общей боевой мощи всей армии атака именно Архов наиболее предпочтительно, опять же если общий урон от закла существенно не превышает общее кол-во здоровья всего отряда Архангелов.

Но в случае если урон от закла всего 100 ед, то в таком случае мы вообще не снижает мощь вражеской армии. Не факт что Арха получится сразу добить, плюс враг может использовать Лечение или Палаткой подличится. А в случае со слабыми и средними героями с небольшой СМ, это проблема.

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

При уроне от закла в 100 ед. и если у всех отрядов верхнее текущее существо имеет полное здоровье, то мы получаем следующее:
1) Архангелы: 0,4 * fight_value_Архов
2) Чемпионы: 1.0 * fight_value_Чемпионов
3) Королевские грифоны: 4.0 * fight_value_Королевских_Грифонов

Вышеописанный алгоритм в данном случае выберет именно Чемпионов, несмотря даже на то, что 0,4 * fight_value_Архов > 1.0 * fight_value_Чемпионов.
При этом если у верхнего существа в отряде Архов осталось 100 ед здоровья, то при том же уроне от закла (100 ед) будет выбран уже отряд Архов в качестве цели.
А вот если урон от закла будет >=250 (но не больше суммарного здоровья стека), то, как и с площадными, будут выбираться Архи, не зависимо от остатка его здоровья.

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

***
UPD: По ходу мы забыли учесть один важный момент - отряды под Слепотой. Для ударных одиночных заклов, а также для дамажащих площадных и, возможно, для Берсерка нужно игнорить отряды на которые уже наложенна Слепота, как мы игнорим имунных.

Кстати, для Берсерка выбор цели сейчас не так как для остальных площадных, а так как для массовых заклов. Вот именно с Берсерком так и нужно, так как это не дамажащий спелл. Здесь как раз этот вариант будет оптимальным (по общей силе всего отряда, так как урона нет). Только вот для отрядов под Слепотой подумать надо. Для дамажащих спеллов по любому нужно игнорить, а вот с Берсерком хз.
Последний раз редактировалось Rolex 07 апр 2021, 13:40, всего редактировалось 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 » 07 апр 2021, 13:30

В dataInit() после строчки stackVector.resize(n); можно вставить условие:

Код: Выделить всё
if ( !ударное_одиночное_заклинание )
{
    sort(stackVector.begin(), stackVector.end(), cmpFightValue);
    stable_sort(stackVector.begin(), stackVector.end(), cmpSpellDuration(spell));
}
else
    sort(stackVector.begin(), stackVector.end(), cmpDamageFightValue(spellDamage));

Таким образом, задача сводится к тому, что Вам необходимо написать компаратор cmpDamageFightValue(spellDamage). Т.е. всего лишь одно условие, которое предпочтёт один отряд другому.

Цитата:
UPD: По ходу мы забыли учесть один важный момент - отряды под Слепотой. Для ударных одиночных заклов, а также для дамажащих площадных и, возможно, для Берсерка нужно игнорить отряды на которые уже наложенна Слепота, как мы игнорим имунных.

Либо не учитывать (случай синглкаста ударного заклинания*), либо учитывать с минусом, а может быть, даже с порядочным минусом (площадные заклинания).

* Можно ставить в самый конец вектора те отряды, которые убиваются кастом.

Так. Мы же кастеры :smile4: Нам наоборот выгодно, чтобы отражённое заклинание снимало Слепоту. Тут уже следует разделять, чьё зеркало отражает :smile2:

Хотя тогда бы получилось несправедливо. Зеркало должно давать преимущество той стороне, на отряде которой висит.
Вернуться к началу

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

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

Сообщение Rolex » 07 апр 2021, 15:08

Преимущество должно быть у того героя на чьих отрядах стоит Зеркало. То есть речь сейчас идет за Слепоту у кастера без Зеркала. Обычно Слепоту ставят на самые сильные отряды, чтобы разобраться с менее слабыми. Потому, думаю, чтобы не ломать тактику, которую выбрал тот или иной игрок, нужно отряды под Слепотой игнорить до тех пор, пока в войске кастера не остануться одни имунные монстры и этот отряд под Слепотой (или же пока не закончится ее действие, или же пока она не будет снята родным героем ---> stack->active_spell_duration[SPL_BLIND] == 0). Если, например, у кастера остались только Черные драконы и этот отряд под Слепотой, вот тогда мы можем на такой отряд отражать дамажащий закл.

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 » 08 апр 2021, 12:43

Если убирать, то для всех. Если оставлять, то тоже для всех.

Для чего нужен этот коэффициент? Всегда полезно представлять крайние случаи. Например, у нас есть три отряда с уязвимостью 1 (т.е. любой каст на них всегда действует) и три более сильных отряда по damageFightValue, но с уязвимостью 0.000001 (одна миллионная). Без множителя алгоритм будет всегда выбирать вторую, более сильную группу отрядов, однако урон будет наноситься только в 1 случае из 1,000,000. Уязвимость показывает, в скольких случаях (например, из 100) урон будет нанесён, а в скольких случаях отряд получит нулевой урон.
Вернуться к началу

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

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

Сообщение Rolex » 08 апр 2021, 13:17

Приемущества все же есть. Но тогда нужно это же делать и для синглкаста и для масскаста.
Последний раз редактировалось Rolex 08 апр 2021, 16:15, всего редактировалось 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 » 08 апр 2021, 16:04

Делается это очень просто:

Код: Выделить всё
// Костыль для C++98
class cmpFightValue
{
    int spell;

public:
    cmpFightValue(int id) : spell(id) { }

    bool operator () (_BattleStackEx_* a, _BattleStackEx_* b)
    {
        return a->getMagicVulnerability(spell) * a->fightValue() > b->getMagicVulnerability(spell) * b->fightValue();
    }
};

class cmpSpellDuration
{
    int spell;

public:
    cmpSpellDuration(int id) : spell(id) { }

    bool operator () (_BattleStackEx_* a, _BattleStackEx_* b)
    {
        return a->active_spell_duration[spell] < b->active_spell_duration[spell];
    }
};

и в dataInit():

Код: Выделить всё
sort(stackVector.begin(), stackVector.end(), cmpFightValue(spell));

В С++11 и выше можно через лямбды, но наша тема, в том числе, для тех, кто компилирует в VS2008. Ещё раз повторюсь: такие плагины, как этот, правильнее сразу писать с использованием H3API, но тема обучающая всё-таки, а H3API иногда меняется. Но не вижу большой проблемы с переносом кода.
Вернуться к началу

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

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

Сообщение Rolex » 08 апр 2021, 16:15

UPD: Хотя нет, лучше убрать. Эти приемущества весьма сомнительны. Все же, лучше оставить это только для гномов и грейженых гномов.

Для (stack->creature_id == CID_DWARF || stack->creature_id == CID_BATTLE_DWARF) делаем это:

Код: Выделить всё
double _BattleStackEx_::damageFightValue(const int spell, const int spellDamage)
{
   return this->getMagicVulnerability(spell) * min((double)spellDamage / this->full_hp,
      this->count_current - (double)this->lost_hp / this->full_hp) * this->creature.fight_value;
};


Для остальных вот это:
Код: Выделить всё
double _BattleStackEx_::damageFightValue(const int spell, const int spellDamage)
{
   return min((double)spellDamage / this->full_hp,
      this->count_current - (double)this->lost_hp / this->full_hp) * this->creature.fight_value;
};


Почему для гнонов и боевых гномов лучше оставить? По моим тестам при заявленых 20% сопротивления к магии у обычных гномов на практике получается в районе 45%, тогда как у грейженных гномов при заявленных 40% на практике получается 55%. У Кристальных драконов при заявленых 20% на практике получается 23-25%, а у Сказочных драконов Волшебное зеркало при заявленных 20% отрабатывает с вероятностью 25-27%.

Объясню, почему я хочу убрать этот коэф.

Изображение

Вот пример, наши Титаны под Зеркалом и находятся между двумя сильными отрядами. Метеоритный дождь, например, наносит 600 ед. урона. Без getMagicVulnerability(spell) будут атакованы только вражеские Архангелы (-2 Арха и -100 ед), вместо всех трех отрядов. Потому как 2 Титана будут явно сильнее 24 Грифонов. С этим же множителем атака идет всех трех отрядов и мы с вероятностью 50% может потерять 2 Титанов (так как суммарное Fight Value 2 Титанов занижается множителем).

Если Зеркало сработало на наших Титанах, то наш профит 24 Королевских Грифона (Архов не считаем, так как мы их и без множителя уничтожает):
Если Зеркало не сработало на наших Титанах, то получается мы теряем 2 Титанов и забираем 24 вражеских Королевских Грифона.

Без множителя мы при любых раскладах убиваем только 2 Архов. Получается, что мы не может дополнительно забрать 24 Королевских Грифона, но в тоже время мы в любом случае сохраняем всех Титанов. Шанс потерять 2 Титанов равен 50 на 50%. Шанс дополнительно забрать кроме 2 Архов еще 24 Королевских Грифона - 100%. Это равносильно тому, что мы может потерять 2 Титанов и забрать 48 вражеских Королевских Грифонов со 100% вероятностью.

Все сводится к тому, сможет ли в бою 1 Титан победить 24 Королевских Грифона. Согласно Fight Value, который заложен разработчиками: Fight Value 1 Титана = 5000, а 1 Королевского Грифона - 364. Якобы 24 * 364 > 1 * 5000 <=> 8736 > 5000. Согласно заложеному Fight Value разработчиков Титан сможет одолеть максимум 13-14 Королевских Грифонов, а 24 должен сливать в одну калитку. Но на практике в бою один на один 1 Титан разбивает даже 24 Королевских Грифона! Лично я в данном случае предпочел бы сохранить 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 » 08 апр 2021, 16:21

Цитата:
Почему для гнонов и боевых гномов лучше оставить? По моим тестам при заявленых 20% сопротивления к магии у обычных гномов на практике получается в районе 45%, тогда как у грейженных гномов при заявленных 40% на практике получается 55%. У Кристальных драконов при заявленых 20% на практике получается 23-25%, а у Сказочных драконов Волшебное зеркало при заявленных 20% отрабатывает с вероятностью 25-27%.

Это никак не подтверждает исходный код.

Цитата:
Вот пример, наши Титаны под Зеркалом и находятся между двумя сильными отрядами. Метеоритный дождь, например, наносит 600 ед. урона. Без getMagicVulnerability(spell) будут атакованы только вражеские Архангелы (-2 Арха и -100 ед), вместо всех трех отрядов. Потому как 2 Титана будут явно сильнее 24 Грифонов. С этим же множителем атака идет всех трех отрядов и мы с вероятностью 50% может потерять 2 Титанов (так как суммарное Fight Value 2 Титанов занижается множителем).

Почему занижается? У Титанов разве есть магическое сопротивление? В сомнительных случаях я бы включал показ информации (showDebugInfo). Мы же вычитаем Fight Value союзных отрядов. Если у Героя есть приличный Resistance, наоборот, алгоритм должен задевать Грифонов, так как разность damageFightValueThem - damageFightValueUs только возрастёт за счёт снижения damageFightValueUs. Не думайте одним кастом. Вероятности имеют смысл, когда кастов несколько (чем больше, тем лучше; в том числе, в разных боях, а не только в этом конкретном).
Последний раз редактировалось AlexSpl 08 апр 2021, 16:32, всего редактировалось 1 раз.
Вернуться к началу

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

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

Сообщение Rolex » 08 апр 2021, 16:30

AlexSpl писал(а):

Почему занижается? У Титанов разве есть магическое сопротивление?

На Титанах же Зеркало и его сопротивление в 50% я так понял учитывается. Иначе как тогда обьяснить, что без вот этого getMagicVulnerability(spell), Титаны с Королевскими Грифонами не атакуються, а только Архи?
Последний раз редактировалось Rolex 08 апр 2021, 16:36, всего редактировалось 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 » 08 апр 2021, 16:33

Цитата:
На Титанах же Зеркало и его сопротивление в 50% я так понял учитывается. Иначе как тогда обьяснить, что без вот этого getMagicVulnerability(spell), Титаны с Королевскими Грифонами не атакуються, а только Архи?

Зеркало не увеличивает резист. Здесь следует отличать резист от шанса перенаправления. А не задевает, потому что алгоритму жаль Титанов больше, чем Грифонов. Проверьте ещё вторичные навыки героев (!). Может, у Вас герой, у которого Титаны, с навыком Resistance или артами.
Вернуться к началу

Пред.След.

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

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

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

cron