Понимание и редактирование случайных миссий
⌨️
Понимание и редактирование случайных миссий

💨 Оглавление

💢 Сложность

Базовым требованием и переменной для случайных миссий является сложность. Это произвольное десятичное число в диапазоне [0, 100] (то есть 0 и 100 включены).

При необходимости максимальную сложность можно изменить с помощью следующих смещений:

content.dll, 1143D4, 100f = максимальное значение сложности misn ~adoxa
content.dll, 1175F0, 100f = максимальное значение сложности DestroyMission (я думаю; это часть StateMachine) ~adoxa
content.dll, 11B22C, 100f = Максимальное значение rank_diff и сгенерированная сложность миссии ~adoxa

Источник, adoxa

⚡ Расчет сложности предложений о работе (mBase.ini)

Ключ к пониманию работы сложности — это способ её использования и расчёта. К сожалению, поначалу это не так просто понять. Основное применение — файл mBase.ini, где задаются значения сложности, которую игрок может получить от базы или NPC.

Показатель сложности, отображаемый в игре при чтении предложения миссии, имеет прямую связь с выбранной технической сложностью. По-видимому, эти игровые показатели где-то жёстко закодированы для определённых значений сложности.

Обычно параметр mission_type можно интерпретировать как:

mission_type = DestroyMission, <mindiff>, <maxdiff>, <chance>

minDiff и maxDiff важны для расчёта реальной сложности, доступной игроку. Особенно важно отметить, что maxDiff` не обязательно соответствует максимальному значению. Расчёты производятся следующим образом (в псевдокоде):

🔭 Одиночная игра

// rank_diff = на основе внутреннего MissionNum и DATA\MISSIONS\rankdiff.ini
// min_diff и max_diff берутся из mission_type/misn в DATA\MISSIONS\mbases.ini
// 0 <= rnd < 1

factor = 1.3689^3

diff1 = rank_diff / factor
if (diff1 < 0)
    diff1 = 0
if (diff1 > 100)
    diff1 = 100

diff2 = rank_diff * factor
if (diff2 < 0)
    diff2 = 0
if (diff2 > 100)
    diff2 = 100

if (diff2 <= min_diff)
    return 0 // become a better pilot

if (diff2 >= max_diff)
{
    d = max_diff / factor
    if (min_diff >= d)
        d = min_diff
    return max_diff - cos(rnd * pi/2) * (max_diff - d) // cos in RAD
}

if (diff1 < min_diff)
    diff1 = min_diff

return max_diff - cos(rnd * pi/2) * (max_diff - diff1) // cos in RAD

🔭 Мультиплеер

// min_diff и max_diff берутся из mission_type/misn в DATA\MISSIONS\mbases.ini
// 0 <= rand < 3
// 0 <= rnd < 1

if (rand == 0)
{
    d = max_diff
}
else
{
    factor = 1.3689^(rand * 2 + 2)
    d = max_diff * factor
}
if (d < 0)
    d = 0
if (d > 100)
    d = 100

return d - cos(rnd * pi/2) * (d - min_diff) // cos in RAD

Источник, adoxa

Если внимательно присмотреться к первой части расчёта, специфичного для многопользовательской игры, то становится ясно, что maxDiff не является итоговым значением, а умножается на случайный коэффициент. Это может привести к тому, что многопользовательские миссии с максимальной сложностью выше 8,1101 уже достигнут суммарного значения 100, если случайные значения максимальны.

Чтобы понять влияние значений minDiff и maxDiff на эти расчёты, рекомендую посмотреть на график для некоторых простых значений.

Чтобы ограничить сложность многопользовательской игры ровно между значениями minDiff и maxDiff, можно применить следующий патч к Content.dll с помощью bwpatchw.

# Установите сложность задания MP точно между минимальной и максимальной сложностью в mbases.ini.
# Jason Hood (adoxa), 22 February, 2010.
# Fixed 3 June, 2010.

File: content.dll # v1.1
0AAD7A: 89 44 E4 04 D9 44 E4 20 D8 64 E4    [ 99 B9 03 00 00 00 F7 F9 85 D2 74 ]
1C EB 04 66 B8 FB 06 DB 44 E4 04            [ 33 D9 05 30 B2 FB 06 DD 5C 24 04 ]
D8 0D D0 97 39 06 DE C9 D8 44 E4            [ FF D6 99 DD 44 24 04 B9 03 00 00 ]
1C 5E 83 C4 10 C3                           [ 00 F7 F9 8D 54 12 ]

Источник, adoxa

⚡ Количество созданных NPC по сложности и уровню NPC (npcranktodiff.ini)

Можно точно определить, сколько NPC определённого уровня будет создано для определённого уровня сложности. Это регулируется в файле npcranktodiff.ini.

Строка выглядит следующим образом:

NpcRank = <npc level>, <difficulty for 1 ship>, <difficulty for 2 ships>, <difficulty for 3 ships>, …

Важно отметить:

  • Для появления корабля в каждой волне задания выбирается только одна строка NpcRank.
  • Количество появляющихся кораблей определяется наивысшим уровнем сложности в этой строке (например, если уровень сложности равен 5, а третий столбец корабля равен 5, то появляются 3 корабля).
  • По умолчанию игра может обрабатывать до 8 кораблей в строке. Чтобы увеличить это количество, см. ниже.

В игре используется таблица весов для определения предпочтительного количества появляющихся кораблей. Она выглядит следующим образом:

Корабли Одиночная игра Мультиплеер
1 0 0
2 3 2
3 9 3
4 6 9
5 2 6
6 1 4
7 1 2
8 1 1

Источник, adoxa

Веса здесь снова указаны относительно их суммы. Например, в многопользовательском режиме сумма равна 27, поэтому 4 корабля появляются в 9 из 27 случаев (33,3%). Как видите, 1 корабль имеет вес 0. Это означает, что игра никогда не выберет такой «NpcRank», которому соответствовал бы уровень сложности только первого корабля. Эту таблицу очень важно помнить. При любом выбранном уровне сложности всегда должны быть определены «NpcRank», охватывающие все эти корабли. Если вы заметили, что ваша доска заданий пустее, чем должна быть, возможно, игра пытается выбрать количество кораблей, не предусмотренное для текущего уровня сложности.

Эту таблицу можно изменить по смещению 11CC58 в Content.dll. Сначала идут веса для одиночной игры (начиная с 0 кораблей, 1 корабля, 2 кораблей и т. д.), а затем — для многопользовательской игры (также начинаясь с 0 кораблей, 1 корабля и т. д.).

Если вы хотите разрешить NpcRank создавать более 8 кораблей, вам необходимо создать собственную таблицу весов.

content.dll 0F8A4B 58CCFB->00CBFC = использовать массив из 30 чисел с плавающей точкой в ​​12CB08 (создан вручную!) для вектора веса корабля SP ~adoxa
content.dll 0F8A54 7CCCFB->80CBFC = использовать массив из 30 чисел с плавающей точкой по адресу 12CB88 (создан вручную!) для вектора веса корабля MP ~adoxa

Источник, adoxa

🔥 Требования к наличию миссий, предлагаемых на базе

Чтобы игроку была предложена миссия определённого уровня сложности, необходимо выполнить 4 условия:

  • У вражеской фракции должен быть NPC любого не связанного уровня/сложности хотя бы в одной зоне описания миссии в системе.
  • У вражеской фракции должен быть хотя бы один NpcShip из npcships.ini, назначенный через faction_prop.ini, который должен иметь тот же уровень, что и любой NpcRank, соответствующий уровню сложности, и иметь npc_class class_fighter.
  • У вражеской фракции должен быть хотя бы один NpcShip из npcships.ini, назначенный через faction_prop.ini, который должен иметь соответствующую npc_class diff-метку + class_fighter для соответствующего NpcRank. Уровень этого NpcShip должен быть не ниже ±1.
  • Должен быть хотя бы один NpcRank, способный создавать корабли в выбранном диапазоне сложности.

Это звучит довольно сложно, поэтому давайте объясним это на примере:

Мы хотим, чтобы какая-нибудь фракция предлагала задания против fc_lr_grp в нашей системе. Для этого нам сначала нужна зона заданий:

[Zone]
nickname = Zone_destroy_vignette_01
pos = 0, 0, 0
shape = SPHERE
size = 10000
mission_type = unlawful, lawful
vignette_type = open

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

[Zone]
nickname = Zone_destroy_vignette_01_pop
pos = 0, 0, 0
shape = SPHERE
size = 100000
toughness = 19
density = 1
repop_time = 25
max_battle_size = 4
relief_time = 35
encounter = area_scout, 1, 1
faction = fc_lr_grp, 1

Теперь нам нужно узнать, какой уровень сложности будет у нашей миссии. Для этого проверим в файле mBase.ini:

mission_type = DestroyMission, 0, 0.112387, 100

С этим значением мы теперь переходим в файл npcranktodiff.ini и ищем соответствующую строку. Имейте в виду, что в игре есть определённые весовые коэффициенты, определяющие количество кораблей, которые она предпочитает создавать (см. главу выше). Один из возможных вариантов NpcRank может быть следующим:

NpcRank = 1, 0.00985, 0.03569, 0.07754, 0.13539, 0.20923, 0.29908, 0.40493, 0.52677

Теперь мы знаем, что хотим создавать NPC 1-го уровня. Теперь нам нужно убедиться, что у fc_lr_grp есть хотя бы один корабль, соответствующий этому, с npc_class, равным class_fighter:

[NPCShipArch]
nickname = fc_lr_pi_fighter_d1
loadout = fc_lr_pi_fighter_loadout01
level = d1
ship_archetype = pi_fighter
pilot = pilot_pirate_med
state_graph = FIGHTER
npc_class = unlawful, class_fighter, d1

Мы видим, что level=d1, что соответствует нашему NpcRank. Кроме того, npc_class содержит d1 и class_fighter, поэтому он также может создать корабль. Важно знать, что должен существовать корабль требуемого уровня. Но это не обязательно должен быть тот же корабль, который создаётся! Корабли, которые будут созданы, определяются по их совпадающей метке npc_class. Это означает, что если у вашего корабля d1, но npc_class d100, он не будет создан. Вы можете и должны иметь хотя бы один (но это может быть другой) корабль с совпадающей меткой npc_class d1 и class_fighter. Важно, что любой корабль с соответствующим npc_class должен совпадать с level +1. Итак, можно сказать, что у нас есть корабль уровня d2 с npc_class=diff1, class_fighter, и он сможет появиться. Но только если где-то определён другой корабль с level=d1. Это может выглядеть так, и корабль всё равно появится в нашей миссии d1:

[NPCShipArch]
nickname = fc_lr_pi_fighter_d1-d2
loadout = fc_lr_pi_fighter_loadout01
level = d2
ship_archetype = pi_fighter
pilot = pilot_pirate_med
state_graph = FIGHTER
npc_class = unlawful, class_fighter, d1, d2

🔭 Оплата по уровню сложности (diff2money.ini)

Определение оплаты за определённый уровень сложности очень просто и понятно выполняется в diff2money.ini. Строка выглядит следующим образом:

Diff2Money = <start difficulty>, <payment>

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