Цитата("Berserker")
Так поиск пути же. Формируется массив из клеток, по которым пойдёт отряд. Длина массива и есть расстояние. Поэтому - расстояние и есть кол-во шагов. Берсерк не смотрел, в функцию расчёта урона передаётся уже кол-во шагов.
Цитата("AlexSpl")
Для пеших понятно. А для летающих?
Цитата("Sav")
А какая разница? Летающие же ничем принципиально не отличаются.
Цитата("AlexSpl")
Цитата
А какая разница? Летающие же ничем принципиально не отличаются.
Под "Берсерком" летающие отряды очень странно вычисляют расстояния:
Berserk 1И особенно:
Berserk 2Цитата("Berserker")
Реализация Берсерка, на мой взгляд, содержит баги и всего-то.
Цитата("phdoc")
Наконец-то собрался написать про формулу расчета урона в части вклада в неё компонента "Удача".
Итак, формула из FizMiG, реализующая алгоритм вычисления урона:
Код
D(sum) = [D(bas)+MD(bas)+M(of)+M(luck)] * [1-M(def)]
где
M(luck)=D(bas)
D(bas) - базовый урон юнита, выбираемый из интервала [Dmin;Dmax]
При реализации алгоритма у себя, столкнулся с нюансом, описанным здесь:
http://forum.heroesland.com/viewtopic.php?f=7&t=193Если коротко про суть проблемы, то заключение о том, что "...в случае срабатывания удачи во время нанесения удара, юнит наносит дополнительно урон равный базовому урону D(bas), определенному для этого раунда боя" (© FizMiG) - не совсем верно. Очень похоже на то, при удаче просто удваивается результирующий "безудачный" урон D(sum).
Цитата("Sav")
Насчёт новых недель и месяцев.
При генерации новой недели в 25% случаев происходит +5 единиц монстра и 75% - ничего (всякие там муравьеды не стоят наравне с монстрами и генерируются отдельно при выпадении этих 75%).
Монстры могут выпасть только принадлежащие городу и только имеющие неотрицательный уровень. При этом в картах RoE (не уверен на 100%, но по всей видимости) не выпадают монстры сопряжения. Шансы всех монстров равны.
При генерации нового месяца в 50% случаев ничего не происходит (всякие дождевые черви и т. п.), в 40% генерируется монстр и в 10% - чума.
Уровень сложности никак не влияет. Единственное - в обучении месяцев монстров и чумы не может быть вообще.
Монстры действительно берутся из указанных в ФизМиГе 12-ти. Шансы выпадения каждого равны.
Количество монстров = (случайное число от минимального количества монстра на карте в начале игры до максимального количества монстра на карте в начале игры) * 2, если оно больше 4095, оно приравнивается к 4095.
Минимальные и максимальные количества легко проверить через erm. Они общие для всех городских существ одинаковых уровней. К примеру, 1-й дегрейд: 20-50, 1-й грейд 20-30, 7-й грейд: 3-8.
Агрессивность появляющихся монстров случайная - от 1 до 10 с равными шансами, эти монстры всегда могут увеличиваться в количестве и убегать.
Количество появляющихся монстров не определено, у каждой доступной (без воды и т. п.) клетки карты есть 0.5% шанса, что на ней появится монстр. То есть теоретически монстры могут появиться сразу на всех клетках или ни на одной.
Всё выяснено по коду. Могу привести доказательства - декомпилированные участки.
Тут была картинка, она умерла.

Цитата("Shurup")
Хотелось бы по уточнений по поводу "случайноси" месяца кого-то. Иногда неделя чумы "лечится" загрузкой автосейва, а иногда нет.
В принципе "случайности" чего-то в героях вообще нужно отдельную статью посвещать.
Цитата("Sav")
Случайные числа, управляющее срабатыванием недели/месяца, так же как и случайные числа, управляющие номером выпавшего монстра генерируются прямо при наступлении новой недели/месяца.
Так что теоретически они "лечиться" должны. Но поскольку, они, скорее всего, основываются на seed'е, то при одинаковом количестве срабатываний ГСЧ при ходе ИИ seed окажется таким же (а значит, таким же будет и результат рандома). Измениться он может либо при какой-нибудь переинициализации (например установки текущего времени в качестве нового seed), либо при неодинаковом количестве срабатывания ГСЧ (что может быть либо от изменённых действий игрока, либо если количеством действий, требующих генерации случайного числа, где-то у ИИ выступило сгенерированное по времени число).
Думаю, как-то так.
Цитата("Berserker")
Приведи декомпилированные участки в псевдокоде 4GL уровня с подсветкой и комментариями.
Ноториально заверенные скриншоты тоже баллов накинут.
Цитата("Sav")
Ну, что есть - то есть.
Код
__int16 __thiscall A0_Town_GrowCreaturesCount_sub_5C01D0(void *this, int SpecCreature1, int SpecCreature2, int SpecAddCount)
{
int MonsterLevel_v4; // ebx@1
int MonsterLevel_v5; // edi@1
int this_v6; // esi@1
int Growth_v7; // eax@2
int CrearureType_v8; // ecx@3
int v10; // [sp+Ch] [bp-4h]@1
this_v6 = this;
MonsterLevel_v5 = 0;
MonsterLevel_v4 = 0;
v10 = (this + 22);
do
{
LOWORD(Growth_v7) = A0_Get_Town_Creature_Growth_sub_5BFF60(this_v6, MonsterLevel_v5);
if ( Growth_v7 > 0 )
{
CrearureType_v8 = Town_Monsters_dword_6747B4[MonsterLevel_v4 + 14 * *(this_v6 + 4)];
if ( CrearureType_v8 == SpecCreature1 || CrearureType_v8 == SpecCreature2 )
Growth_v7 += SpecAddCount;
if ( *(this_v6 + 1) == -1 )
LOWORD(Growth_v7) = Growth_v7 / 2;
*v10 += Growth_v7;
}
++MonsterLevel_v5;
++MonsterLevel_v4;
v10 += 2;
}
while ( MonsterLevel_v5 < 14 );
return Growth_v7;
}
Код
SpecCreature1_v71 = -1;
SpecCreature2_v64 = -1;
dword_6977A0 = 0;
NewWeek_Monster_dword_69844C = RandInt_sub_50C7C0(0, 14);
SpecAddCount_v68 = 5; // + 5 единиц
if ( *(this_v1 + 64288) != 4 ) // Не новый месяц
{
if ( RandInt_sub_50C7C0(1, 4) == 1 )
{
dword_6977A0 = 1;
Monster_type_v3 = *(this_v1 + 32166) != 0 ? 144 : 117;// В зависимотсти от типа карты: если RoE, то 117
if ( (*(this_v1 + 32166) != 0 ? 0x1B : 0) != -118 )
{
Monste_info_v4 = &(*off_6747B0)[29 * Monster_type_v3];// Информация о монстре
do
{
if ( *(this_v1 + 32166)
|| Monster_type_v3 != 112 && Monster_type_v3 != 113 && Monster_type_v3 != 114 && Monster_type_v3 != 115 )// Воздушный, земляной, огненныи и водный элементали
{
if ( *Monste_info_v4 != -1 ) // Если монстр - из города
{
if ( Monste_info_v4[1] >= 0 ) // Если монстр имеет уровень >= 0
++v2; // Учитываем его в количестве монстров
}
}
Monster_Type_Check_v5 = Monster_type_v3--;
Monste_info_v4 -= 29;
}
while ( Monster_Type_Check_v5 );
}
v8 = *(this_v1 + 32166);
v7 = Rand_sub_61842C() % v2;
v6 = v8 != 0 ? 144 : 117;
if ( (v8 != 0 ? 0x1B : 0) != -118 )
{
v9 = &(*off_6747B0)[29 * v6];
do
{
if ( v8 || v6 != 112 && v6 != 113 && v6 != 114 && v6 != 115 )
{
if ( *v9 != -1 )
{
if ( v9[1] >= 0 )
{
if ( v8 || v6 == 112 || v6 == 113 || v6 == 114 || v6 == 115 || *v9 != 8 )
{
v10 = v7--;
if ( v10 <= 0 )
break;
}
}
}
}
v11 = v6--;
v9 -= 29;
}
while ( v11 );
}
NewWeek_Monster_dword_69844C = v6;
SpecCreature1_v71 = v6;
}
}
v14 = 0;
v12 = 0;
v13 = *(this_v74 + 34181);
while ( v13 )
{
v15 = (*(this_v74 + 34182) - v13 + ((-1240768329i64 * (*(this_v74 + 34182) - v13)) >> 32)) >> 8;
if ( v14 >= (v15 >> 31) + v15 )
break;
v16 = *(this_v74 + 34181) + v12;
if ( *(v16 + 4) == 3 && qword_66CE68 & *(v16 + 336) )
{
dword_6977A0 = 2;
SpecCreature2_v64 = 43; // Чёрт.
SpecCreature1_v71 = 42; // Бес.
SpecAddCount_v68 = (*off_6747B0)[1235];
NewWeek_Monster_dword_69844C = 42;
break;
}
++v14;
v12 += 360;
}
v18 = 0;
for ( i = 0;; i += 360 )
{
v19 = *(this_v74 + 34181);
if ( !v19 )
break;
if ( v18 >= (*(this_v74 + 34182) - v19) / 360 )
break;
A0_Town_GrowCreaturesCount_sub_5C01D0(
(i + *(this_v74 + 34181)),
SpecCreature1_v71,
SpecCreature2_v64,
SpecAddCount_v68);
++v18;
}
Код
v1 = RandInt_sub_50C7C0(1, 10);
if ( dword_6977A0 != 2 ) // Нет бога огня (недели бесов)
{
if ( v1 <= 5 || *(this_v2 + 128669) ) // Если это обучение, то никаких монстров не появляется
// Если это не обучение - появляется в 50% случаев
{
dword_698884 = 0;
v3 = RandInt_sub_50C7C0(0, 9);
}
else
{
if ( v1 > 9 )
{
dword_698884 = 2; // Неделя чумы
goto LABEL_10;
}
dword_698884 = 1;
v3 = New_Month_Creatures_byte_63E678[RandInt_sub_50C7C0(0, 11)];
}
dword_697798 = v3; // Тип существа
goto LABEL_10;
}
dword_698884 = 1;
dword_697798 = 42; // Бес
LABEL_10:
v4 = 0;
v17 = 0;
LABEL_11:
v5 = *(this_v2 + 34181);
if ( v5 )
{
v6 = (*(this_v2 + 34182) - v5 + ((-1240768329i64 * (*(this_v2 + 34182) - v5)) >> 32)) >> 8;
if ( v4 < (v6 >> 31) + v6 )
{
Creature_Level_v19 = 0;
CreaturesInTow_Count_Offset_v7 = 22;
while ( 1 )
{
if ( v4 == -1 )
Town_Info_v8 = 0;
else
Town_Info_v8 = *(this_v2 + 34181) + 360 * v4;
if ( A0_Get_Town_Creature_Growth_sub_5BFF60(Town_Info_v8, Creature_Level_v19) > 0 )// Если прирост > 0
{
if ( dword_698884 != 1 )
goto LABEL_23;
if ( dword_6977A0 != 2 // Нет бога огня (недели бесов)
&& Town_Monsters_dword_6747B4[Creature_Level_v19 + 14 * *(Town_Info_v8 + 4)] == dword_697798 )// Существа соответствуют существам месяца
{
*(CreaturesInTow_Count_Offset_v7 + Town_Info_v8) *= 2;// Удваиваем количество
LABEL_23:
if ( dword_698884 == 2 ) // Неделя чумы
{
*(CreaturesInTow_Count_Offset_v7 + Town_Info_v8) -= A0_Get_Town_Creature_Growth_sub_5BFF60(
Town_Info_v8
,
Creature_Lev
el_v19);// Отнимаем прирост (который был дан за новую неделю)
if ( *(CreaturesInTow_Count_Offset_v7 + Town_Info_v8) < 0 )// Избегаем отрицательного количества
*(CreaturesInTow_Count_Offset_v7 + Town_Info_v8) = 0;
*(CreaturesInTow_Count_Offset_v7 + Town_Info_v8) >>= 1;// Уменьшаем оставшееся колчество вдвое
}
goto LABEL_27;
}
}
LABEL_27:
CreaturesInTow_Count_Offset_v7 += 2; // Переходим к следующему существу города
++Creature_Level_v19;
if ( CreaturesInTow_Count_Offset_v7 > 50 )// Если существа в городе закончились, переходим к следующему городу
{
++v17;
v4 = v17;
goto LABEL_11;
}
v4 = v17;
}
}
}
if ( dword_698884 == 1 ) // Если неделя с удвоением существ...
{
for ( i = 0; i < *(this_v2 + 130120) + 1; ++i )
{
v18 = 0;
if ( dword_6783C8 > 0 )
{
v9 = dword_6783CC;
do
{
v10 = 0;
if ( v9 > 0 )
{
do
{
v12 = *(this_v2 + 32528) + 38 * (v10 + *(this_v2 + 32529) * (v18 + i * *(this_v2 + 32529)));
v11 = *(v12 + 12);
if ( !(HIBYTE(v11) & 0x10) )
{
if ( v11 & 0x40 )
{
v13 = *(v12 + 4) & 0xFF;
if ( v13 != 8 )
{
if ( v13 != 9 )
{
if ( *(v12 + 30) != 26 )
{
if ( RandInt_sub_50C7C0(1, 200) == 1 )
{
A0_Place_Object_sub_4C9550(this_v2, v10, v18, i, 71, dword_697798, 0);
*v12 ^= (*v12 ^ (2
* RandInt_sub_50C7C0(
(*off_6747B0)[29 * dword_697798 + 27],
(*off_6747B0)[29 * dword_697798 + 28]))) & 0xFFF;// Случайное число: от минимального стартового значения на карте до максимального
*v12 = *v12 & 0xFFFE0FFF | ((RandInt_sub_50C7C0(1, 10) & 0x1F) << 12);// Агрессивность от 1 до 10, может убегать и увеличиваться
}
}
}
}
}
}
v9 = dword_6783CC;
++v10;
}
while ( v10 < dword_6783CC );
}
v15 = __SETO__(v18 + 1, dword_6783C8);
v14 = v18++ + 1 - dword_6783C8 < 0;
}
while ( v14 ^ v15 );
}
}
sub_4CA0D0(this_v2);
}
Цитата("Berserker")
Сав, с тобой, я смотрю, шутки плохи )))
Цитата("Adept")
Цитата
(Sav @ 28 Dec 2011, 18:22) Ну, что есть - то есть.
Я в кодах не разбираюсь, но было у меня такое впечатление (основанное сугубо на практике), что генерирующиеся монстры принадлежат только к тем городам, которые есть на карте. То есть, если на карте скажем Некрополис и Замок, плюс пара нейтральных Оплотов и Башен, то недели импов/гоблинов/гноллов не будет.
Это и подразумевалось под «монстр из города» или нет и у меня ошибочное представление?
Цитата("Sav")
Нет, просто при составлении выборки подходящих монстров для случайного выбора проверяется тип города монстра, и если он равен -1 (т. е. не принадлежит никакому городу вообще, у него на фоне при промотре нет форта города), то монстр не попадает в выборку.
Правда, есть отдельная проверка на монстров сопряжения - они не могут выпасть на картах RoE.
В месяце же монстра может выпасть любой из 12, независимо вообще ни от чего (он просто выбирается из специального списка монстров месяца, безо всяких проверок).
Цитата("Sav")
Шансы выпадения у сказочного дракона того или иного закла:
- Ледяная молния: 16/153
- Удар молнии: 17/153
- Огненный шар: 21/153
- Волшебная стрела: 15/153
- Кольцо холода: 20/153
- Цепная молния: 19/153
- Метеоритный дождь: 23/153
- Инферно: 22/153
Генерируются при получении хода на основе специальной таблицы; шанс = (номер заклинания)/(сумма номеров всех доступных для выпадения заклинаний).
Цитата("Sav")
Хм, сейчас подумал, - вышеописанная ситуация, скорее всего, является багом. Дело в том, что на самом деле таблица с заклинаниями для дракона содержит 16, а не 8 значений. Но используются они через одно, начиная с первого, остальные не используются вообще. Видимо, вторые значения - это шансы (о чём говорит так же их преимущественная круглость), вместо которых по ошибке используются номера. Завтра приведу здесь всю таблицу.
Цитата("Crodo")
А на сказочных драконах, случайно, нет постоянного волшебного зеркала?
Цитата("Sav")
Есть, но не как заклинание, а как свойство (т. е. не снимается и, возможно, имеет другие проценты и механику).
Цитата("Adept")
Цитата
(Sav @ 28 Dec 2011, 03:11) ... поскольку, они, скорее всего, основываются на seed'е..
А что что это самое «seed»? И что ещё от него зависит? Ну либо где про него можно почитать подробнее.
Цитата("Sav")
Обычно случайные числа генерируются по какому-нибудь сложному математическому алгоритму, который принимает на вход какое-то число и возвращает непредсказуемый результат (для бытового понимания, понятно что на самом деле любой математический алгоритм даёт предсказуемый результат). При этом результат сначала возвращается в виде какого-то большого числа, которое потом при помощи, например, взятия остатка от деления по нужному делителю, преобразуется в число из нужного диапазона.
Результат (имеется ввиду "большое" число до преобразования) является текущим seed'ом и используется как входное число при следующей генерации. При этом, т. к. это математический алгоритм, при одинаковых входных данных он будет возвращать одинаковые результаты. Поэтому, если в какие-то моменты времени seed'ы будут одинаковыми, то и последовательности случайных чисел будут одинаковыми.
Иногда (как минимум - при запуске игры или карты - надо же брать откуда-то входные данные для первой генерации) в качестве seed берётся текущее время, что нарушает одинаковость последовательностей и делает числа действительно случайными.
Чтобы где-то об этом было хорошо написано, я не знаю, возможно, гугл по ГСЧ или ГПСЧ выведет куда-нибудь.