Свой сервер

Killing Floor: количество мобов на волне, MaxZombiesOnce и задержка между сквадами

В 2016 году на killingfloor.ru спросили, как сделать, чтобы мобы выходили больше и быстрее, не трогая настройки песочницы: поднять MaxZombiesOnce и сократить паузу между сквадами. Flame ответил разбором KFGameType.SetupWave() и таймера спавна. Здесь его краткое изложение.

Мутанты Killing Floor от Клота до Патриарха в двух вариантах текстур Весь состав мутантов Killing Floor, от Клота до Патриарха, в двух вариантах текстур. Каждый из них учитывается в лимитах ниже.

Два разных ограничения

ПеременнаяСмысл
TotalMaxMonstersСколько мобов всего будет за волну (не одновременно)
MaxMonstersСколько мобов может быть живо одновременно. На практике равна MaxZombiesOnce

Во время волны мобы спавнятся, пока число живых не дойдёт до MaxMonsters. Убили моба — число упало — появляется новый. И так, пока не кончится общий лимит волны.

Как SetupWave считает мобов

  1. Берётся WaveMaxMonsters текущей волны из массива Waves:
Waves[0]=(WaveMask=2013265920,WaveMaxMonsters=20,WaveDuration=180,WaveDifficulty=3.000000)
  1. Умножается на модификатор сложности:
СложностьGameDifficultyМодификатор
Новичок10.7
Нормально2+1.0
Сложно, Самоубийственно4, 51.3
Ад на земле71.7

Комментарий в коде всё ещё называет ветку 7+ «Suicidal»: он написан до появления «Ада на земле».

  1. И на модификатор числа игроков (игроки плюс боты):
Игроков123456больше
Модификатор122.753.544.5игроки × 0.8
  1. Результат ограничивается:
NewMaxMonsters = NewMaxMonsters * DifficultyMod * NumPlayersMod;
TotalMaxMonsters = Clamp(NewMaxMonsters, 5, 800);
MaxMonsters = Clamp(TotalMaxMonsters, 5, MaxZombiesOnce);

Clamp(x, min, max) держит x в пределах отрезка. Отсюда два вывода:

  • Стандартный KF никогда не даст больше 800 мобов за волну, что бы ни стояло в WaveMaxMonsters. Чтобы снять предел, нужно поменять константу в SetupWave() своего геймтайпа. В SRGameType из темы стояло Clamp(NewMaxMonsters,5,1100).
  • TotalMaxMonsters почти всегда больше MaxZombiesOnce, поэтому MaxMonsters на деле равна MaxZombiesOnce.

Пример: 6 игроков на «Аде на земле» при WaveMaxMonsters=20 дают 20 × 1.7 × 4.5 = 153 моба за волну, одновременно живых не больше MaxZombiesOnce.

Где что прописывать

  • Waves — config-массив, объявленный в Invasion. Каждый унаследованный геймтайп читает свою секцию, так что если в KillingFloor.ini есть секция [ServerPerks.SRGameType] со строками Waves, значения берутся оттуда.
  • MaxZombiesOnce объявлена в KFGameType как globalconfig и читается только из [KFMod.KFGameType]. В [ServerPerks.SRGameType] её менять бесполезно.
[KFMod.KFGameType]
MaxZombiesOnce=64

Интерфейс песочницы не даёт поставить больше 64, но в ini значение может быть выше. Подумайте, прежде чем это делать: у игроков со слабыми ПК начнутся тормоза, а к 6-й волне нагрузка копится и вылезает рассинхрон (пропадает оружие, не видно мобов). 64 — разумный потолок, а ускорить спавн сквадов обычно полезнее.

Пауза между сквадами

В таких обсуждениях всегда всплывает WaveStartSpawnPeriod, но, по разбору кода от Flame, эта переменная нигде не используется. Настоящая задержка находится в Timer() состояния MatchInProgress, в ветке bWaveInProgress:

if ( nextSpawnSquad.length > 0 )
    NextMonsterTime = Level.TimeSeconds + 0.2;
else
    NextMonsterTime = Level.TimeSeconds + CalcNextSquadSpawnTime();

Пока сквад выставляется, мобы идут каждые 0.2 с. Между сквадами пауза берётся из CalcNextSquadSpawnTime(), в среднем около 1.5 с на «Аде на земле». Чтобы спавн шёл почти непрерывно, переопределите состояние в своём геймтайпе и поставьте константу:

state MatchInProgress
{
    function Timer()
    {
        // copy the whole stock KFGameType.MatchInProgress.Timer() body here,
        // then replace the NextMonsterTime branch with:
        NextMonsterTime = Level.TimeSeconds + 0.2;
    }
}

Скопируйте тело стандартного Timer() целиком и поменяйте только эту строку. Остальные функции состояния копировать не нужно.

Что делает CalcNextSquadSpawnTime()

Стандартную функцию KFMod.KFGameType.MatchInProgress.CalcNextSquadSpawnTime() Flame выложил в теме «Популяция монстров» на форуме killingfloor.ru (вопрос был, как заставить мобов быстрее выходить из спаунеров, если MaxZombiesOnce поднят до 64). Базовое значение — KFLRules.WaveSpawnPeriod, дальше оно умножается на коэффициенты по числу игроков:

ИгроковРанние волныПоздние волны
3 и меньше1.0 (без изменений)1.1
40.851.0
50.650.75
6 и больше0.30.60

«Ранние волны» — это WaveNum < 2 для короткой игры, WaveNum < 4 для обычной и WaveNum < 7 для длинной. При своей длине игры (GL_Custom) коэффициенты ранних волн (0.85 / 0.65 / 0.3) действуют на всех волнах. На «Сложно» и выше (GameDifficulty >= 4.0) время дополнительно умножается на 0.85. В конце синусоида добавляет «пики и спады» интенсивности спавна:

SineMod = 1.0 - Abs(sin(WaveTimeElapsed * SineWaveFreq));
...
NextSpawnTime += SineMod * (NextSpawnTime * 2);

Поэтому менять нужно переменную var() float SineWaveFreq; — она задаёт частоту этой синусоиды, а с ней скорость и интенсивность появления зедов.

WaveCountDown — совсем другое: это отсчёт времени у трейдера между волнами, а не задержка спавна.

Итог

ЦельГде
Мобов одновременноMaxZombiesOnce в [KFMod.KFGameType]
Мобов за волнуWaveMaxMonsters в Waves, в секции своего геймтайпа
Больше 800 за волнуПоменять Clamp в своём SetupWave()
Быстрее сквадыПереопределить MatchInProgress.Timer() в своём геймтайпе
Время между волнамиВремя трейдера, а не код спавна

Вопросы и ответы

Почему MaxZombiesOnce в секции [ServerPerks.SRGameType] ничего не меняет?
MaxZombiesOnce объявлена в KFGameType как globalconfig, поэтому читается только из секции [KFMod.KFGameType] файла KillingFloor.ini, какой бы геймтайп ни стоял на сервере.
Меняет ли WaveStartSpawnPeriod задержку между появлением мобов?
По разбору кода на killingfloor.ru — нет: эта переменная в коде игры нигде не используется. Пауза между сквадами берётся из CalcNextSquadSpawnTime().