Killing Floor 2

Killing Floor 2

Controlled Difficulty
blackout  [developer] Jun 4, 2017 @ 4:18am
Released build 013bcb (2017-06-14) [old hash: 7ddf76]
This release has been in development and testing for a while. Special thanks to Trance for invaluable help identifying and reproducing important bugs.

A note on spawnrate bottlenecking. Recent gameplay videos have shown teams killing zeds faster than the spawnmanager replaces them. This is a major concern for teams pushing high difficulty. The new SpawnPoll and CohortSize options definitively solve this spawnrate bottlenecking problem. To give an extreme example, I've tested CohortSize=64 SpawnPoll=0.250 MaxMonsters=200 FakePlayers=15 on Outpost, which results in 192 zeds spawning within 500 milliseconds (half a second). This is an absurd example just intended to show that bottleneck has been removed, not a recommendation for playable settings. The rest of this post has more info CohortSize, SpawnPoll, and lots of other changes.

This release was mostly developed before the sideshow update was announced and pushed. The most hastily-added and least-tested new features in this release are the FleshpoundRageSpawns option and SpawnCycle syntax for mini FPs, king FPs, and raged FPs. Insofar as this release has bugs, they are likely to be related to sideshow and perhaps to involve these options. Please keep this in mind as you play with this release.

Check out CD's new docs:

NEW DOCUMENTATION

https://github.com/notblackout/kf2-controlled-difficulty/blob/master/readme.md

If you're trying this release, click that link above. It's worth checking out. I'm copying the TOC here because most people won't bother even if I beg.

* Getting Started[github.com]
* Advice on CD configuration tuning[github.com]
* Chat Command Reference[github.com]
* Client-side Config Options[github.com]
* Console Commands[github.com]
* Dynamic Settings Reference[github.com]
* Frequently Asked Questions[github.com]
* Configuration Option Reference[github.com]
* Basic Server Setup[github.com]
* SpawnCycle reference[github.com]

Most of those pages are new or rewritten. Only the SpawnCycle reference and the FAQ are old content.

Draft Changelog

I haven't updated the changelog.txt yet, but here's a short and possibly incomplete changelog:

  • CD now records realtime spawnrate statistics during each non-boss wave. It prints these stats to global chat during trader time or after everyone dies.

    http://steamcommunity.com/sharedfiles/filedetails/?id=939475212

  • Added "Dynamic Settings". Many CD settings can now be optionally configured to automatically adjust themselves as players join and leave, and as the game advances through the waves. This can be used to automatically increase the intensity as more players join and the waves progress, and to dial it back down if a player leaves. Dynamic Settings only change between waves.

    http://steamcommunity.com/sharedfiles/filedetails/?id=939476353

    Click here to see the new documentation for Dynamic Settings:

    Dynamic Settings Reference[github.com]

  • These options support Dynamic Settings: CohortSize (new), FakePlayers, MaxMonsters, SpawnMod, SpawnPoll (new), ZTSpawnSlowdown (new), and (all new) BossFP, FleshpoundFP, ScrakeFP, TrashFP. You can make them dynamic using ini file definitions or a mathematical function definition. Or, you can use the options just like any other option, without any dynamic stuff.

  • New option: CohortSize=int. Before this release, the spawnmanager would only try to spawn one squad at a time. The typical squad was about 4.5 zeds. This could bottleneck the spawnrate. CohortSize helps solve this (along with SpawnPoll described below). When CohortSize is positive, CD's spawnmanager spawns as many squads as necessary until either CohortSize zeds have spawned on that attempt, the MaxMonsters limit is reached, or the map's available spawnvolumes have been filled. CD will use as many of the map's spawnvolumes as necessary to spawn the cohort, iterating from most to least preferred by spawnvolume-preference-score. On larger maps (e.g. Outpost), this makes it possible to spawn something like 64 zeds instantaneously. For example, let's say CohortSize=12. Let's also say that no zeds are currently alive, that MaxMonsters=20, and that the SpawnCycle dictates squads with alternating sizes 4, 5, 4, 5, etc. When the spawnmanager next wakes up, it will spawn the first squad of 4 zeds at the most-preferred spawnvolume, the next squad of 5 zeds at the second-most-preferred spawnvolume, and the first 3 of 4 zeds in the third squad at the third-most-preferred spawnvolume. The 1 zed leftover from the final squad goes into LeftoverSpawnSquad and becomes a new singleton squad that attempts to spawn on the following spawnmanager wakeup, just like in vanilla KF2. All three squads just described appear to spawn simultaneously from the player point of view; a "spawnmanager wakeup" is effectively instantaneous to us. Let's continue the example and consider the next spawnmanager wakeup. Assume no zeds were killed. We have 12 alive and MaxMonsters is 20. The single-zed LeftoverSpawnSquad spawns at the most-preferred spawnvolume. Now we resume the spawncycle at a squad of size 5. This spawns at the second-most-preferred spawnvolume. There are now 12 + 1 + 5 = 18 zeds alive. The spawnmanager finishes this cohort by spawning 2 of the 4 zeds in the next squad, putting the 2 other zeds that could not spawn into LeftoverSpawnSquad. This cohort was only 1 + 5 + 2 = 8 zeds, not 12, because we reached the MaxMonsters limit of 20.

  • New option: SpawnPoll=seconds. This sets how often the spawn manager wakes up. It's now recommended to set SpawnMod=0 and just tweak this value instead. This used to be hardcoded by TWI and in older CD release to one second. Unlike with SpawnMod, even small changes can have enormous impact on spawnrate. For instance, changing from 1.0 to 0.1 means zeds spawn ten times as fast. This also removes time variance from the spawn system: the spawnmanager always wakes up every SpawnPoll, and if you also set SpawnMod=0, it will try to spawn every time it wakes up. Only MaxMonsters or the map's spawnvolumes being so physically congested that there is literally nowhere for a new zed to spawn can prevent the spawnmanager from doing its work every SpawnPoll seconds, assuming SpawnMod=0. SpawnMod=0 completely nullifies any other delays, including the spawn delay built into the map, the spawn delay TWI setup for early waves, TWI's sine mod spawn delay, or whatever else. Setting SpawnMod=0 means that the only option affecting spawn timing is this new SpawnPoll setting, and, to a lesser extent during zed time, the new ZTSpawnSlowdown option (described in the next bullet).

  • New option: ZTSpawnSlowdown=float. This controls how zed time does -- or does not -- affect the spawn manager's timer. If set to 1.0, then zed time has no effect on the spawn manager's timer. If set to a positive number, then the spawn manager's poll timer runs that many times slower during zed time, effectively giving the players a spawn reprieve proportional to the length of the zed time. This requires another new setting, ZTSpawnMode=clockwork, but that is set by default. To revert to the vanilla interaction between the spawn manager wakeup interval and zed time (which is pretty convoluted, but roughly proportional to ZTSpawnSlowdown=1.5), set ZTSpawnMode=unmodded.

  • New option: ZedsTeleportCloser=true|false. This controls whether zeds are allowed to teleport closer to players. This is always happening behind the scenes in TWI's vanilla KF2, and CD kept that behavior until now. This option now lets you decide whether to allow this teleporting. False means zeds can't teleport to try to get closer to players. True means they can. If a zed believes it has become physically stuck, then it can still teleport regardless. This helps a little with "in-your-face" teleports around corners and behind doors a player kites, but it doesn't completely remove that effect as long as zeds are still spawning. When new zed squads spawn, they tend to choose spawnpoints around corners or behind doors near kiting players, much like a teleporting zed might have chosen. So those new squads can still pop up unexpectedly and give a sensation of "in-your-face" surprise, even though existing zeds can't teleport.

    http://steamcommunity.com/sharedfiles/filedetails/?id=939505611

  • New option: FakePlayersMode=add|replace. Controls whether FakePlayers are added to the human player count or replace the human player count. "add" is the default. "add" is consistent with CD's old behavior before this release; "replace" is the new alternative. This option also affects the new BossFP, FleshpoundFP, ScrakeFP, and TrashFP options (described in the next bullet point).

  • New options for zed HP scaling: BossFP, FleshpoundFP, ScrakeFP, TrashFP. These options all take integer values. They behave like a fake players modifier that is specific to the head and body health scaling functions for their respective zed types. "Trash" here means everything that is not a fleshpound, scrake, or boss (volter/patriarch). Like FakePlayers, all of these options are affected by FakePlayersMode.

  • New option: FleshpoundRageSpawns=true|false. Controls whether fleshpounds can spawn raged. TWI's sideshow update, which dropped after five iterations of this release's betas and just before I hoped to push to the workshop, added a random chance for FPs to spawn enraged on suicidal and HOE. This option lets you disable this behavior.

  • SpawnCycle support for minifleshpounds. The SpawnCycle documentation has been updated.

    SpawnCycle Documentation[github.com]

  • SpawnCycle support for deterministically enraging minifleshpounds and fleshpounds of your choosing. Suffix the FP or MFP squad with a "!" character to make it spawn enraged. Note that the user can still override this, forcing the squad to spawn unenraged, by setting FleshpoundRageSpawns=false. The SpawnCycle documentation has been updated to discuss this too. See the same link as above.

  • EXPERIMENTAL SpawnCycle support for fleshpound kings, denoted by FP*. This was another last-minute change prompted by the chaos of TWI's sideshow update. It might be altered or removed in future CD versions!

  • New chat commands for every option mentioned above. For example, !cdbossfp and !cdspawnpoll are both new.

  • Reformatted !cdinfo with some new setting displays and concision tweaks. For instance, if an option in !cdinfo output is configured to run on a bilinear:1.5_2.0P*4.0_5.575W;50max function, that would really clutter !cdinfo's output. So, it just prints "[bilinear]". To see the full definition in cases where !cdinfo's brief form has suppressed it, run the cd chat command for that option (e.g. !cdmaxmonsters) or "!cdinfo full".

    http://steamcommunity.com/sharedfiles/filedetails/?id=939473743

  • New client-side option: AlphaGlitter=true|false. Controls the glowing red particle effects emitted when an albino alpha zed does an AOE rally. Setting true means these rallies look and behave exactly like in the unmodded game (default). Setting false disables the particle effects associated with AOE rallies, but none of the behaviors. Also, the albino alpha performing the AOE rally will still play a little air bubble animation, and a small light circle will still appear under his feet. Just no particles. This makes it easier to see. This option lives in the ControlledDifficulty.CD_PlayerController subsection of KFGame.ini on the client. It can only be modified by editing this file. It cannot yet be modified in-game.

  • New client-side options for chat limiting: ChatCharThreshold and ChatLineThreshold. CD's gotten a bit chattier. Don't like it spamming your chat window? Now you can specify character and line maxima for chat messages sent by CD. Messages that exceed either maximum will be printed in full only to the console. The chat window will only show a single line reading "(See Console)" when this happens. These options live in the ControlledDifficulty.CD_PlayerController subsection of KFGame.ini on the client. They can only be modified by editing this file. They cannot yet be modified in-game.

  • New command !cdwho. Prints names of connected players. Prints a status char next to each name indicating whether the player is alive/dead (if during a wave), or ready/unready (if during warmup), or a spectator.

  • Increased FakePlayers cap from 32 to 160 (5x). This permits wave sizes up to slightly over 1.5k.

  • Added basic_moderate using long waves 1, 4, 7, 10. Thanks to Kore for testing this combination of SpawnCycle waves. I added Kore to the authors field on the basic_moderate preset.

  • Temporary Hotfix: Scrake Head Rage: KF2's sideshow update introduced a bug affecting how scrakes estimate their current head health percentage when deciding to rage. On HOE, this made a single 9mm headshot rage a 1p scrake. I've added a workaround to CD that resores ordinary scrake rage behavior with respect to head health. This workaround could be reverted whenever TWI fixes the problem upstream. Note: this does not fix `spawnai scrake`. Regularly spawned scrakes are fixed, but scrakes spawned with cheat commands are not fixed. Here's a discussion of the gory details, in case you're curious:

    https://github.com/notblackout/kf2-controlled-difficulty/blob/master/Classes/CD_Pawn_ZedScrake_v1053Hotfix.uc

  • New docs! So useful it's worth repeating: https://github.com/notblackout/kf2-controlled-difficulty/blob/master/readme.md

Download Link

This build is on the steam workshop.

Past Beta Revisions

All of the following builds are outdated. The current steam workshop build (what you get when you click CD's subscribe button) is newer. These links are retained only as a record of what happened in the beta iterations.

The first beta build in this thread was https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-04-33b79b.

The second build, https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-07-7c359e, included a fix for BossFP/FleshpoundFP/ScrakeFP/TrashFP scaling.

The third build, https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-08-74b08e, made AlphaGlitter client-side, made bilinear dynamic setting round instead of truncate when governing integer options, and changed the bilinear syntax to bilinear;a_b*x_y,zmax to work around an engine limitation.

The fourth build, https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-09-cea5d4, removed the CDAlphaGlitter console command but kept the client-side AlphaGlitter option in KFGame.ini's ControlledDifficulty.CD_PlayerController section. It can only be changed by manually editing that file.

The fifth build, https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-09-1d17bb, fixed post-wave recap's spawnrate calculation in cases where the team wiped before the full wave of zeds could spawn.
Last edited by blackout; Jun 15, 2017 @ 8:17pm
< >
Showing 1-9 of 9 comments
blackout  [developer] Jun 5, 2017 @ 9:29am 
I'm aware that MaxMonsters (and probably integer settings in general) is using integer truncating instead of rounding when using a bilinear program. An example is MaxMonsters=bilinear:1_1*16_20 in a long game. Under float-to-int trucation, the transition from MM 16 to 17 happens between waves 3 and 4. The beta exhibits this behavior.

Under rounding, that transition would happen between waves 2 and 3.

I think rounding is more intuitive and I intend to change all integer settings to round instead of truncate under bilinear programming before release. I actually had it setup that way for most of my pre-beta testing, but I touched some bits shortly before releasing the beta that caused an unintentional switch to truncation.
Trance Jun 6, 2017 @ 11:33pm 
For the 'FleshpoundFP'-type commands, it isn't clear that it is always an add-type mode rather than replace-type. I first thought that FakePlayersMode would affect the 'FleshpoundFP' value, but it does not. I'm not sure if anyone else might have found that a little confusing.
blackout  [developer] Jun 7, 2017 @ 7:27am 
@Trance huge thanks for the comment. This helped me find and fix an important zed HP bug in the beta that specifically affected solo play.

FakePlayersMode is intended to apply to FleshpoundFP and the other *FP options, so your comment surprised me. Acting on your comment, I searched for and eventually found an HP-related bug, but the underlying cause was independent of FakePlayersMode.

I first checked HP with these commands (after spawning a braindead fleshpound).

getall KFPawn_ZedFleshpound Health getall KFPawn_ZedFleshpound HealthMax getall KFPawn_ZedFleshpound HitZones

Health and HitZones[HZI_HEAD] values appeared correct in all of my *FP/FPM scenarios. But something was clearly wrong, because FleshpoundFP=6 and FakePlayersMode=replace in solo only required 33 SCAR headshots to decap a FP, which is wrong. If I spawned one or two human pawns with those same settings, decap took 41 headshots, the correct amount. I started digging...

I eventually discovered that the CD beta overlooks and fails to scale a variable called GameResistancePct (GRP) on KFPawn_Monster. This variable affects incoming damage taken by the zed, and it depends on player count. This seems bizarrely overdetermined -- why have scalable zed hp AND a scalable global resistance muliplier when they look largely redundant? -- but it matters.

CD should have included BossFP/FleshpoundFP/ScrakeFP/TrashFP, modulated by FakePlayersMode, in GRP's calculation. CD included neither. This was the bug.

GameResistancePct's calculation in the standard game is convoluted, but the ultimate result is simple. In the standard game, GRP is set to 0.75 in solo (1 player) and 1.0 in every other case (players > 1). This is why SCAR decap shot count only changed when going from solo to one pawn (33 -> 41), and did not change when going from one pawn to two pawns (41).

You might be thinking: 0.75 has no obvious mathematical relationship to 33/41, even after generous assumptions about rounding, and you'd be right. GameResistancePct is not a direct multiplier or divisor on damage taken. The function responsible for applying GameResistancePct to incoming damage is KFPawn_Monster.AdjustDamage. It is pretty baroque. That function applies GRP to incoming damage, but for headshots, another "ExtraHeadDamage" formula term is later added to the result. The relationship is more like a linear function with constant offset.

Thanks again, Trance. This was the only HP related bug I could find, but please do let me know if I've misunderstood your report or you think there's another bug in there. For my part, I now plan to do some headshots-to-decap/bodyshots-to-kill tests later with a variety of damage types in different *FP/FPM configurations to check that the results match what would be expected in the standard game with braindead pawns, just in case I've missed some other obscure hp-related catch. I did several such tests before publishing the new beta, but only with the SCAR and in an ad-hoc fashion.

The new github release is

https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-07-7c359e

with attached CD.u artifact

https://github.com/notblackout/kf2-controlled-difficulty/releases/download/beta-2017-06-07-7c359e/ControlledDifficulty.u

I will update the main post.
Trance Jun 7, 2017 @ 12:57pm 
Great, you're the man blackout! I wasn't exactly sure about what was wrong, but I knew SOMETHING was wrong when I tried FleshpoundFP=6, ScrakeFP=6 and FPM=replace and the result wasn't true 6P health, so I figured I'd let you know. Of course you found out and fixed the issue in short order.

I'll play with it more to see if there's anything that's still off.
blackout  [developer] Jun 7, 2017 @ 6:10pm 
I've been tweaking the beta source a bit. I expect to upload another beta build tomorrow.

I have the following changes in my local repo, lightly tested and ready to go:

* Converted AlphaGlitter from a server-side to client-side option. Trance pointed out that the original AlphaGlitter didn't work in multiplayer, which drove me to reimplement it purely client-side; thanks! Now every player can choose their own glitter preference independent of the server and other players. Still works in solo too.

* Converted all integer-valued dynamic settings from using float truncation to float rounding

I would like to address two other items before uploading:

* "bilinear:..." causes problems when given on the `open` command line. The engine seems to ignore the entire `open` command when it includes a parameter with a colon in it. Maybe there's an escape syntax that I don't know about yet. ", ', and \ did not appear to help. Anyway, if I can't find an escape, I may have to choose a different separator character to replace the colon, one that is compatible with `open`. I would update the parser and the accompanying docs in that case.

* Write a new client.md (or something) doc describing the existing client side options: CDAlphaGlitter, CDChatLineThreshold, CDChatCharThreshold, CDClientLogging. The doc should also note that this client-side state resides in KFGame.ini's ControlledDifficulty.CD_PlayerController section rather than the server-side ControlledDifficulty.CD_Survival section.

That's my plan.
Last edited by blackout; Jun 7, 2017 @ 6:13pm
blackout  [developer] Jun 8, 2017 @ 5:30pm 
I implemented the items described in my last post.

The most important item is CDAlphaGlitter, a new client-side command. Run `CDAlphaGlitter false` in your console to disable alpha glitter. This works both standalone and in networked play. It is persistent (saves to your KFGame.ini in [ControlledDifficulty.CD_PlayerController]).

Then I made a new github release:

https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-08-74b08e

CD.u artifact:

https://github.com/notblackout/kf2-controlled-difficulty/releases/download/beta-2017-06-08-74b08e/ControlledDifficulty.u

This is the new console command documentation:

https://github.com/notblackout/kf2-controlled-difficulty/blob/master/console.md

I will update the main post.
Last edited by blackout; Jun 8, 2017 @ 5:34pm
blackout  [developer] Jun 9, 2017 @ 4:39pm 
Trance, who is a bug reporting hero, found that issuing `cdalphaglitter false` reliably causes his entire client to crash so hard that it does not even bugsplat. This is extremely alarming. Generally, it shouldn't even be possible for unrealscript to cause an engine crash. Furthermore, the code in question is pretty innocuous: it converts its string param to a bool, assigns a config var, and then invokes the SaveConfig() function that ships with the engine.

I was initially unable to reproduce this over about a dozen attempts. After Trance provided a video showing exactly what he did, I was able to reproduce it -- once. Another dozen attempts all failed to reproduce. I do not think I changed anything. At one point after the first crash, I tried using a copy of his *PlayerController* KFGame.ini sections, in case my client managed to mutate them whereas his didn't, to no avail.

My one crash left no minidump file. It also left a logfile abruptly truncated multiple lines before the crash actually occurred, as though the engine's internal logfile buffer did not have time to flush before the program terminated. This contrasts with bugsplat crashes, where the engine typically writes an obfuscated stacktrace to the logfile and leaves behind a .dmp file.

SaveConfig() is a native function provided with the engine (declared on Object.uc, the root of the inheritance hierarchy). I cannot see the source for it. It seems improbable that there could be a bug in such a fundamental function, but the observed hard-crash behavior could be consistent with a bug in native code.

I cannot reliably reproduce this, see the engine code in question, or get any real handle on exactly what's causing it or why it would appear to manifest nondeterministically, so I've decided to remove the CDAlphaGlitter console command (and a couple of other commands that are less interesting but used the same pattern).

The AlphaGlitter client-side option will live on, but editing it will require manually editing KFGame.ini. I would have liked the added convenience of the CDAlphaGlitter get/set console command, but the uncertainty involved is far too great for the convenience. If I can eventually work out what's going on here and prove that the problem has been avoided or fixed, then I would consider reintroducing that command.

New github beta release:

https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-09-cea5d4

New CD.u artifact:

https://github.com/notblackout/kf2-controlled-difficulty/releases/download/beta-2017-06-09-cea5d4/ControlledDifficulty.u

New documentation page naming the client-side options, what they do, and where to find/change them:

https://github.com/notblackout/kf2-controlled-difficulty/blob/master/client_config.md

(I will update the main post after finishing this comment)

In case anyone's curious or knows more about this than I do, this is the source that the command would have executed or did execute during crashes (though it's not actually clear whether this block was reached before the engine died):

https://github.com/notblackout/kf2-controlled-difficulty/blob/a588449833b51284a31e84f786fbd6847bced871/Classes/CD_PlayerController.uc#L166-L179

I cannot thank Trance enough for all the testing he's done on this beta. This release will be dedicated to him.
blackout  [developer] Jun 9, 2017 @ 4:55pm 
I just found another (far more minor) bug. After a wipe, CD printed the number of zeds that spawned out of the total that could have, e.g. "42/191", the total time between first spawn in wave and last, e.g. 28.6 s spawning, and then the spawnrate as a decimal number. However, CD used the wrong number in the spawnrate numerator; keeping with the example, it used 191 instead of 42. So the spawnrate was always calculated as though the full wave had spawned, even the team wiped before that could happen.

This was easy to spot and fix. I've just committed a fix and made yet another beta release:

https://github.com/notblackout/kf2-controlled-difficulty/releases/tag/beta-2017-06-09-1d17bb

New CD.u artifact:

https://github.com/notblackout/kf2-controlled-difficulty/releases/download/beta-2017-06-09-1d17bb/ControlledDifficulty.u

Main post update incoming
blackout  [developer] Jun 12, 2017 @ 9:40am 
Barring discovery of severe bugs, I hope to push the current beta to the workshop this Friday.

When that happens, I will edit this thread's main post to convert it from a beta announcement into a release announcement.
Last edited by blackout; Jun 12, 2017 @ 9:41am
< >
Showing 1-9 of 9 comments
Per page: 1530 50