Left 4 Dead 2

Left 4 Dead 2

View Stats:
Tsuey May 5, 2019 @ 6:15am
Dev Thread: Map fixes for Valve
On and off I've been working with Rayman1103 on a series of map fixes (exploits included with an extremely finite scope) contained within _commentary.txt files that Valve can assess for adding to the game. Unlike SourceMod or Stripper:Source or straight map re-compiles, the limitations of _commentary.txt's are vast and the majority of my time is developing solutions that work but have some minor downside they'd in no way ever be approved.

The following people have offered different forms of assistance like ideas, criticisms, development, testing, or moral support -- in order of contact:

HUMAN BEAN ------ ᴿᴱᴻᴱ™ ------ ๖ۣۜℳĭđŋĭġђŧ ------ ✔ Hυѕку™

m30w ------ ########## ------ Lux ------ NF ------ Bozo The Clown

Sir ------ JAiZ ------ Master_64 ------ **********

A simple example is Tabbernaut's Stripper:Source fix of the No Mercy 4 elevator[github.com] which works but is incompatible with a stuck-warp Jockey/Charger attack inside the elevator (Survivors end up getting stuck in that clip rather than falling to their deaths). The best fixes need to be discreet and in some cases support exploits that have debatable legitimacy -- though, it's looking like this particular exploit will need to be cut in order to maximize elevator integrity (the trade-off: the 100% can never fall to their deaths and jump all they want, as the 1% lose an attack 50% would consider cheating).

Some examples on things which will be available for testing first (in coming weeks, even months, it's important to be very critical of this type of work):

  1. Absolute elimination of players falling through No Mercy 4 elevator with the added benefit of being able to jump inside it
  2. New canonical LOS blockers for Infected VS spawning on Death Toll 5 docks and Blood Harvest 5 barricade to compensate for the horde exploits there (restricted from updating NAV / scripts so this is the workaround)
  3. Less stupid Dead Center 1 Tank spawns in VS
  4. Miscellaneous exploit fixes (all shortcuts have player-moderated votekicking with a patch amnesty given the game's age & Infected out of map exploits which require teamwork are also ignored, amongst others to be detailed sometime later)

Every single exploit and map bug is being evaluated, most of which are either acceptable Public vanilla VS gameplay (if it's remotely debatable it stays in, unlike Competitive Configs with aggressive rulesets) or just impossible to properly fix with _commentary.txt files (i.e. if a Tank can block a chokepoint with rocks removing the hittable is not a solution).

This thread is to be populated over the long-term for purposes of community outreach and transparency. Plenty of discussion already took place in this otherwise irrelevant thread and it was more suitable to create a devoted thread in a relevant place for purposes of targeting Dedicated Server owners who I hope will assist with testing these fixes on a large scale.

This is a long-term project and -- in its initial state -- this thread is to serve for awareness now, and feedback / testing over time.

The goal is to serve a single VPK with updated _commentary.txt files to Valve that are so extensively vetted they can be absolutely assured that a copy/paste into the live game will not break anything. If Valve doesn't integrate these fixes, that's OK too, we know we tried and it can be demonstrated that Valve prefers to keep L4D2 as it is.
Last edited by Tsuey; May 27, 2019 @ 9:17pm
Originally posted by Tsuey:
ProdigySim was really nice to take the time to interview myself and Jacob as a developer commentary for the update's Versus content, with more planned if people like this sort of thing:

https://www.youtube.com/watch?v=27lFQod69X4

This is a video guide for using the ShowUpdate() feature to render all the VScript changes:

https://www.youtube.com/watch?v=eKrOtGaLWAs

Always and forever, all the VScript code for the map exploit fixes and Versus content will be public here (even if there is a lag for it to get here, we'll be much more open about future pursuits):

https://github.com/Tsuey/L4D2-Community-Update

And most discussion about the update has recently taken place here:

L4DNation Discord
https://discord.gg/FkpqBYF
< >
Showing 121-135 of 153 comments
Tsuey Aug 29, 2019 @ 7:13am 
NO MERCY 1 "HELLO WORLD" LADDERS :: PART I

Dead Center 1 has no ladders to clone, so the iconic beginning of L4D2 isn't getting any re-work... but No Mercy 1 will be a sight to behold...

It's rather upsetting that the only ladder in the start area of No Mercy 1 is seen immediate use by jumping all the way off the starting building, to climb from ground level to reach an adjacent building that's not much higher.

The start area has been pumped full of several new ladders:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448859

The Obvious

No-brainer:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448993

This placement will not risk interference with the Smoker / Death Charge attack across this ledge (as I wouldn't want a new ladder blocking that line), and makes use of wall stains already present from Valve as visual justification for climbability.

No more jumping off and climbing that tall ladder just to get to this simple rooftop.

The Window

This ladder required so much internal argumentation to finally get right:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449115

Ultimately made possible by the lax r_drawclipbrushes 2 clippings which are Survivor-only, intended toward reducing Survivor success rates of the classic L4D1 shortcut:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449195

My history with this ladder is... complicated. I always first envisioned adding a fire escape prop here to allow SI players to attack from that -- but I can't add anything that'd make the Survivor shortcut easier:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448249

I've also dreamt about letting SI players just straight-up go through the window, which is surprisingly possible by killing the func_playerinfected_clip and func_illusionary gate -- before learning Vscript, I forever assumed this was impossible without killing all func_illusionary in the map, but now technically I can isolate any arbitrary entity without a targetname for deletion... but just because I can, doesn't mean that I should:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449253

Overall, my final ladder (the top-most screenshot shown) has a lot going for it:
  1. Originally I was only going to have the ladder go up to the window, but quickly opted to find a taller one to go all the way to the rooftop. This will allow players a quicker way back up, and necessarily position them for a jump to another new ladder.
  2. A new trim was added to the window. This trim has Disabled Collision, but is supplemented with a env_physics_blocker that is Infected only to allow players to climb the ladder, mount this trim ledge, then Smoke / Spit / Boom through the window. The glass can be broken from the outside. Survivors cannot land on this trim so it will not impact the shortcut at all. While I technically could allow players through this window into the inside, that'd require removing the gate which would make it seem odd for Survivors that they cannot jump out of an empty window -- but, ultimately, for the sake of balance it was opted that Survivors should only have to worry about Smokers / Spitters / Boomers from this window.
  3. The added pipe might look a little cluttered, but I hope it doesn't -- players must have Options > Video > Effect Detail set to at least Medium to see all of Valve's default props here (in addition to rooftop structures on maps like Dead Air 3, so the pipe was added to act as SOME climb visualization for low-specs where it'd appear the SI is just climbing a bare wall.
  4. Ladder "guards" on each side of my new ladders will be added -- but at a much later date, because they're just higher entity count for virtually no benefit besides an extra "kick" toward professionalism. It just so happens that Valve's clipping gives me one here by dumb luck.

I avoided adding any ladders to the windows on the opposite side:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449318

If I was to completely "clean up" this area, I'd remove the jeep trigger_hurt down there as well -- but that's not within my project's scope, especially considering that SI players may make conscious use of this to kill themselves off if they just want to die. It would be potentially exciting to add a ladder here, plus more ledge trims, to allow a Smoker / Boomer through the windows over the shelves, but there's now 3 (originally 2) entry points into this immediate area so given how over-powered that'd be, I'm ignoring this idea. Adding any ladder here would increase SI player traffic here from virtually none to existent, leading to inevitable accidental deaths on the trigger_hurt, requiring me to remove it, which isn't within my rights or scope to do so.

The AC Unit

Added these 2 ladders:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449061

And from there, a ladder to the highest rooftop in the start area (this rooftop will be re-surfaced at a later date, just be sympathetic of the immense work ahead of me!):

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449539

This ladder is intended to be climbed after The Window. Ground-level ladders to high rooftops are discouraged both for terms of balance but also aesthetic and feel. Historically, this AC vent existed higher up in L4D1, and in L4D2 Valve removed it outright, the community saw it sorely lacking, and it's one of the things (the alarm clock amongst them) that Rayman1103 added back into the game via _commentary.txt files. While I technically could delete this AC vent as it's only a prop_dynamic then create a ground-level ladder to the top, not only would that violate sense of balance but also history, as well.

It's also important that I don't establish some difficult precedent for myself by making this thick pipe model climbable -- I have the luxury that the one I've modified is perfectly straight, whereas Valve's other derivations are jagged justifying them not having ladders:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449481

As mentioned in a previous post, light poles estalished a messy precedent for me that only resulted in gross, unavoidable inconsistency -- here that's not the case.
Last edited by Tsuey; Aug 29, 2019 @ 7:35am
Tsuey Aug 29, 2019 @ 7:27am 
NO MERCY 1 "HELLO WORLD" LADDERS :: PART II

The Fire Escape

I needed to provide a 2nd ladder to get to the highest rooftop in this area, so instead of adding a decal or a pipe just used the window textures already there:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449624

Deliberately, this is another new ladder that isn't climbable from ground-level, forcing SI players to invest some creativity and most importantly time to reach it. Once across from the ladder, they can make a narrow leap-of-faith across, jump from the adjoined fire escape, or jump and even ascend the distant fire escape.

The Pain In The Ass

I had a lot of problems figuring out this ladder:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448921

Arguably, I don't consider this ladder overpowered because any attack that occurs with the Survivors outdoors, still up here at spawn, simply started prematurely and unfairly. But, the goal is to allow SI players complete rooftop access, and this roof also requires killing a specific func_playerinfected_clip.

It was a pain because I needed to clone the tallest available ladders which were too tall and sunk into playable space below:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448792

The top trim also acted as a significant lip, which I couldn't workaround in manners like this because ladder collision gets wonky after a tilt of about 8 degrees:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448605

I also couldn't combine 2 ladders because the texture scrolling wasn't reasonable to make seamless:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448740

It was also very important to me to allow Survivor players to run around the start area on the ledges in a full circle without colliding with unseen ladders, so I needed to minimize the distance it was away from the wall at the bottom -- ultimately landing on this ideal angle, with a single cloned ladder:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848448488

Also, I didn't want to greatly interfere with anything potentially present in the L4D1 intro cinematic, but given the presence of a stairs platform that's not in the final game, I opted to not worry about it:

https://www.youtube.com/watch?v=eCM9RDkHSEM

Neat: Moviemaking Process: Left 4 Dead's Intro Movie (Dec 4, 2008 - Jason Mitchell[www.l4d.com].

FUNC_ILLUSIONARY

The vast majority of Valve's "wrongway signs" for Infected are prop_static and I can't reasonably remove them -- but there's one here, that can be removed just by killing a specific func_illusionary:

https://steamcommunity.com/sharedfiles/filedetails/?id=1848449678

So that's an example of a new decent Charger spawn that'd be made available.
Last edited by Tsuey; Aug 29, 2019 @ 7:28am
Tsuey Aug 30, 2019 @ 7:59am 
SKYBOX NULLIFICATION & QoL

This is one of several quality of life improvements coming with Versus Ladder Rework -- something no one's ever bothered to do probably because of how much work is required to achieve a negligible result that will go un-appreciated / un-noticed by the vast majority.

Screenshots

What you're about to see are DebugDrawBox() renderings of the trigger_multiple bounding boxes which can be created server-side -- contrary to my lengthy belief, new triggers of virtually any kind can be created server-side without cloning brushes which already exist (as is otherwise required for new ladders).

These trigger_multiples 100% "encase" skybox brushes to negate their presence by teleporting players through them.

To anyone who plays on modified servers that kill both func_playerinfected_clip or in this specific case of DARK CARNIVAL 1 it's env_player_blockers, bringing your Tank up to this rooftop and then squeezing yourself around the sliver of skybox is a familiar sight:

https://steamcommunity.com/sharedfiles/filedetails/?id=1849320136

https://steamcommunity.com/sharedfiles/filedetails/?id=1849320062

And when it comes to BLOOD HARVEST 5 -- the most versatile test-case-of-a-map there is -- there's a skybox separating the start and finale areas. The top screenshot is what happens when noclipped into the skybox's ceiling causing the entire map to render, and the bottom is when that's not the case with the skybox and portals doing their job:

https://steamcommunity.com/sharedfiles/filedetails/?id=1849320266

https://steamcommunity.com/sharedfiles/filedetails/?id=1849320327

_commentary.txt

As of yesterday I have officially hung up my _commentary.txt coat and completely obsoleted their necessity with methods I'll discuss another day.

My _commentary.txt for DARK CARNIVAL 1 (for its infamous purposes of example here) originally contained all of this which 100% worked, with Vscript only needed for handling of that tsu_antiskybox_teleport function:

info_gamemode { mapupdate 1 targetname tsu_auto connections { "OnVersus" "antiskybox_trigmult_1addoutputmins -5 -116 00-1" "OnVersus" "antiskybox_trigmult_1addoutputmaxs 5 116 3920-1" "OnVersus" "antiskybox_trigmult_1addoutputsolid 20-1" } } trigger_multiple { mapupdate 1 filtername filter_infected_global targetname antiskybox_trigmult_1 origin "2780 3252 -648" startdisabled 0 spawnflags 1 allowghost 1 connections { "OnStartTouch" "worldspawnRunScriptCodetsu_antiskybox_teleport(^x^, 2780, 40)0-1" } }

To note several things above:

  1. It's absolutely necessary that new trigger_multiples have their mins and maxs set via AddOutput rather than in the entity definition itself. It's just a quirk of theirs. The solid 2 is necessary to make it collidable.
  2. I've since defined that filter_infected_global in Vscript obsoleting the above, but when it comes to filter_activator_team and other filter entities, all filters which pre-exist in Valve's maps are "painted" onto the brushes they're associated with at map load and cannot be changed whatsoever -- a hidden perk of mins/maxs created triggers is that they don't have brushes, so can be changed at any time, thus leaving no timing gotcha's with regard to creating filters via Vscript.
  3. Spawnflags 1 means that it triggers only for Clients, as opposed to NPC's, Pushables, Physics Objects, debris, etc.
  4. The allowghost 1 makes complete sense as Ghost Infected will also need to be teleported by these clips -- I'm lucky that Valve ever even added this somewhat obscure feature given that its primary use seems to be as kill triggers in place of actual trigger_hurts.
  5. The ^x^ within the function is only a replacement for nested quotes in _commentary.txt -- Vscript uses actual escape charaacters instead.

100% Vscript Equivalent

Turns out it was a lot easier than I thought it'd be to convert **all** this to Vscript.

All my anti-skyboxes will be called upon in this fashion inside a vlr_defaults.nut file:

script tsu_antiskybox_maker("antiskybox_vscript_1", "-4.2 -116 0", "4.2 116 392", "x", Vector(2780, 3252, -648), 40.5)

This function makes the triggers and assigns it a completely dynamic OnStartTouch Connection dependent on the user_ input parameters.

Its first order of business is to understand what the "x" input means, then to look at the provided coordinates for the trigger and "keepsake" either its X or Y value which will be used later. It's important to note that this anti-skybox approach will only work with areas where skyboxes are at perfect 90-degree angles to the world, because mins/maxs do not support angles. Luckily, this is effectively every single important occurrence of them in-game.

The nightmare was all the string concatenations to create the command, which uses worldspawn (rather than a new devoted logic_script as I've done in the past, so it's 1 less entity), to run the function, the \" being an escape character so " is seen as a literal quote inside the RunScriptCode (the ^ substitute is _commentary.txt only, I tried), then the axis, another quote, location, and finally the offset I'll discuss later.

Finally, the _commentary.txt entity data is replicated in Vscript code form. Note that given the fact that player whereabouts must remain highly-responsive, it's virtually impossible to do this without a trigger_multiple because Thinks only execute 10 times per second which would always lead to players noticing when they've suddenly hit the skybox wall pointblank and fall / lose all momentum.

::tsu_antiskybox_maker <- function ( user_strTargetname, user_strMins, user_strMaxs, user_strAxis, user_vecOrigin, user_intOffset ) { local location = null; switch( user_strAxis ) { case "x": location = user_vecOrigin.x; break; case "y": location = user_vecOrigin.y; break; } local command = "worldspawnRunScriptCodetsu_antiskybox_teleport(\"" + user_strAxis + "\", " + location + ", " + user_intOffset + ")0-1"; SpawnEntityFromTable( "trigger_multiple", { targetname = user_strTargetname, filtername = "filter_infected_global", startdisabled = 0, spawnflags = 1, allowghost = 1, origin = user_vecOrigin, connections = { OnStartTouch = { cmd1 = command } } } ); EntFire( user_strTargetname, "AddOutput", "mins " + user_strMins ); EntFire( user_strTargetname, "AddOutput", "maxs " + user_strMaxs ); EntFire( user_strTargetname, "AddOutput", "solid 2" ); }

This beautiful function takes in the familiar "x" from above (which can be defined as the "translation axis"), the "location" (defined as the "middle" of that axis), and the "offset" (defined as the distance the player will be teleported).

This was originally conceptualized as having 1 trigger_multiple on each side of the skybox, but this switch( strAxis ) allows it to all be done with 1 not 2. As always with > < signs, I was in panicked waters here but solid pseudocode before going in required my only needing to flip them once to achieve desired result:

::tsu_antiskybox_teleport <- function ( strAxis, intLocation, intOffset ) { local position = activator.GetOrigin(); switch( strAxis ) { case "x": if ( position.x < intLocation ) { activator.SetOrigin( position + Vector( intOffset, 0, 0 ) ); break; } if ( position.x > intLocation ) { activator.SetOrigin( position - Vector( intOffset, 0, 0 ) ); break; } case "y": if ( position.y < intLocation ) { activator.SetOrigin( position + Vector( 0, intOffset, 0 ) ); break; } if ( position.y > intLocation ) { activator.SetOrigin( position - Vector( 0, intOffset, 0 ) ); break; } } }

I should note that in the final package, all the above code (except the function call itself, addressed again further below) will be function declarations in file global_commentary_txt.nut -- but I have a lot going into mapspawn.nut as well such as one universal filter for all maps just in case Valve hadn't added one already (all maps have Survivor filters, but very few Infected):

SpawnEntityFromTable( "filter_activator_team", { targetname = "filter_infected_global", Negated = "Allow entities that match criteria", filterteam = 3 } );

Fine-tuning

Looking at this again:

script tsu_antiskybox_maker("antiskybox_vscript_1", "-4.2 -116 0", "4.2 116 392", "x", Vector(2780, 3252, -648), 40.5)

Within the function call there's 2 notable values in particular: (1) the -4.2 and 4.2, and (2) the 40.5. For this specific anti-skybox trigger teleporter, the skybox brush was exactly 8 units thick.

If the padding on both sides was exactly 4, the trigger would be inaccessible -- it was also inaccessible at 4.05's, somewhat at 4.1, with the "ideal safety thickness" being 4.2. If it's too thin players won't teleport and if it's too thick they'll have to be teleported further to over-shoot the trigger's bounds just enough to be able to immediately turn right back around and re-enter the trigger to go back -- because we don't want players to be teleported to the other side still inside the trigger unable to immediately back up into it again.

Likewise, if that padding is too thin it was theoretically expected to cause SI players to "hit their head" earlier and lose jump / pounce / charge momentum when going through. This actually turned out to be somewhat false, because values ranging from +/- 4.05 to 10 and higher had negligible difference, all of them resulted in Hunters being anchored down from the air mid-pounce or Chargers colliding with the skybox wall therefore stumbling.

It turned out that this thickness needed to be as high as 35 to 50 to result in Hunters and Chargers not getting "stopped" by the skybox, given that there was more than ample "padding" for collision with the trigger to register and the Vscript to do its job. The problem with this is explained by the last value, in the above case 40.5. The thicker the trigger is, the longer the distance players will need to be teleported across, with the aforementioned values of 35 to 50 needing to be accompanied with teleports of 80+ units.

It was necessary to strike a balance between all of these for the best values:
  1. My highest priority is for SI players who are Spawned or Ghosted to be able to freely move through the skybox brush un-hindered. When they're just running, walking, or doing ordinary jumps through, it does its job with a teleport distance to the most minimalistic extent possible (of 40.5 rather than 80+) where the navigational benefit should vastly exceed the mild jankyness of portal/visarea-popping.
  2. Hunters can still pounce through the skybox but they'll get anchored losing their momentum, and Chargers will collide and stumble at the wall -- BUT both acts, will always transition the player to the other side, which is the most important thing. While this could be fixed with greater thickness, being teleported over twice the distance is much more noticeable and visually intrusive.
  3. Players can go through the teleports as repetitively and rapidly as they wish. With regard to Survivor line-of-sight to a Tank on this rooftop, they don't have great LoS anyway so there shouldn't be any way for the Tank to "abuse" constantly moving back and forth through the teleports -- maybe to dodge a molotov it'd be cheap, but servers using this wouldn't have molotovs anyway.
  4. I have achieved my highest priority very VERY smoothly for Spawned and Ghosted run speeds -- though, admittedly not as much as I was hoping but I don't think any improvement is feasible given those higher Hunter / Charger attack velocities coupled with trigger collision, Vscript, and I/O timing limits. I could see a workaround equivalent to say that of a double-jump where the Hunter / Charger attack is re-upped on the exit side of the teleport, but in the end I'd rather the player just be stopped altogether for these niche, rare spots than being able to use them to exploit somehow.

At its core, anti-skyboxing is a quality-of-life improvement -- but I'm sure I'll come to find out that it introduces brand new attack opportunities, I've just not yet found them.
Last edited by Tsuey; Aug 30, 2019 @ 9:07am
Tsuey Sep 13, 2019 @ 9:01am 
ANTI-SKYBOX'S INEVITABLE LIMITATIONS

I've since improved my teleport / trigger_multiple code to "delete" skybox brushes for Infected players, accomplishing the goal of facilitating movement on the ~10 rooftops throughout the game it's relevant, including the ability for Chargers to charge through skybox brushes... but, I have to accept that this is one of those things that can never possibly be perfect without a BSP recompile.

Visibility, areaportals, etc. are just a fundamental part of binary space partitioning / BSP files[en.wikipedia.org]. We can clone ladders and do a lot of things... even forcing specific leafs to render one at a time:

"cl_drawleaf" = "999" ( def. "-1" ) client cheat "cl_leafsystemvis" = "1" ( def. "0" ) client cheat "mat_leafvis" = "0" cheat - Draw wireframe of current leaf "r_drawleaf" = "-1" cheat - Draw the specified leaf.

But forcing the draw of all leafs, and server-side? It's literally impossible.

Tank Rock Teleportation

Boomers cannot vomit through skybox brushes, and neither can Smokers pull, Spitters spit, or Tanks throw rocks -- the rocks of which collide with and explode just as if they had hit any ordinary wall. Vomit and pulls aren't reasonable to allow with Vscript, but acid balls and rocks probably are but are debatable.

Notice the z_vomit_debug 1:

https://steamcommunity.com/sharedfiles/filedetails/?id=1850126026

You can, however, shoot and kill through skybox brushes:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861974759

The only real question that lies ahead is: should an effort be made to teleport Tank rocks through skybox brushes?

The problem here lies with this screenshot:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861946498

For this common Dark Carnival 1 Tank, the Tank wouldn't be able to see the Survivors camping the streets and would have to throw blindly. Or -- as was the original intent with these skybox teleports -- the Tank can step a few units forward and simply teleport through the skybox brush for a full, un-hindered view:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861946572

The Tank could also jump-haymaker through the skybox brush -- but as it stands, the Tank cannot throw a rock through it, because I'm not teleporting mid-flight rocks. I'm not doing that, because it's (admittedly) more work for something I personally see imbalanced, since the goal going in was always intended to make player movement smoother.

From the opposite direction, if a Survivor got high enough they'd be able to see the Tank through the skybox brush at this direction -- but if the Survivors were (for whatever reason) fighting the Tank at the top of the hill, the Tank would be able to take cover behind the skybox brush as an "invisibility shield" where rocks could be thrown with Survivors not being able to see the Tank at all:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861946661

And there's a thicker skybox brush next to this one -- which I've also "deleted" -- which completely makes everything on either side invisible (instead of only one direction):

https://steamcommunity.com/sharedfiles/filedetails/?id=1861946727

Hard Rain 2 and 3 have another rooftop of interest: "deleting" it will allow Infected players to attack from the top of the roof!

But we also have the Tank most commonly spawn in this spot, which this is what it looks like when on the "outside" of the skybox-enclosed space:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861946879

And this is what it looks like behind the skybox brush -- the Tank cannot see the Survivors, so if rocks were teleported through, they'd be throwing blindly:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861946790

However, if a Survivor were boomed, their silhouettes would show through:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861947145

And this is what is looks like to Survivors (the Tank tossing a rock just to demonstrate that it hits the skybox) -- the Survivors can at least shoot at and damage the Tank, though, so that at least makes this less stupid:

https://steamcommunity.com/sharedfiles/filedetails/?id=1861947062

If the Survivors could not see the Tank at all in the above scenario, the debate for NOT teleporting rocks through would be very strong -- but, seeing as Survivors CAN see that tank, it seems justified to at least "experimentally implement" the teleporting of rocks through skybox brushes... since in the end, it's the Tank playing out the strategy, and throwing rocks semi-blindly is their decisive risk that doesn't screw over the Survivors (at least in this case).

Overall, I'm still not exactly sure how to proceed here, since this is one of those things that are fundamentally impossible to perfect without a BSP recompile... but, given that I'm tackling basically everything possible, ladders will be added to these rooftops, and the skybox brushes will be "deleted" to the greatest possible extent.

Furthermore, this allows me to appreciate just how perfect my cloned ladders are because there's no trade-offs, players won't notice anything different with them at all...so, it's quite demoralizing to be working on anti-skyboxes which will definitely stand out regardless of whatever I do, but somebody needed to do it.
Last edited by Tsuey; Sep 13, 2019 @ 9:18am
Tsuey Sep 13, 2019 @ 1:49pm 
Some other useless tests

There is some level of server-side control regarding visibility, but none of it will be useful with regard to skyboxes. When it comes to actual areaportal entities, I think I exhausted all that you can really do with them -- and none of them change anything for the better at the actual skybox brushes. Deleting sky_camera (which is the 3D skybox and not necessarily the skybox brushes as that's probably worldspawn instead) will also crash the game.

As far as I know, areaportal open/close is normally a part of entity I/O with regard to doors. My mindset was to shoot for broad, sweeping changes just to verify this was a waste of my time.

Following are just some examples so I never have to tinker with these again.

ent_fire func_areaportal open:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862222593

ent_fire func_areaportal close:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862222520

ent_fire func_areaportal open:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862201111

ent_fire func_areaportal close:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862201199

ent_fire func_areaportal open:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862210326

ent_fire func_areaportal close:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862210234

ent_fire func_areaportalwindow setfadeenddistance 1000
or ent_fire portalbrush* disable:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862210447

ent_fire func_areaportalwindow setfadeenddistance 999
or ent_fire portalbrush* enable:

https://steamcommunity.com/sharedfiles/filedetails/?id=1862210386
Last edited by Tsuey; Sep 13, 2019 @ 1:58pm
Tsuey Sep 18, 2019 @ 11:19am 
The End of Quality (of Life)

I still need to work on automation / an editor of sorts, but the deeper I go the more new tech I keep realizing that I want -- and when it comes to Quality of Life (QoL) I'm gratefully done.

Obsoletion of skybox brushes was always approached from a QoL perspective but will have vast changes on various map's play -- but the one thing that's purely and simply exclusively a QoL fix is Dead Center 3's ladders.

It has been requested by several people for their climbing to be made less stupid, and I've finally struck the definitive balance.

Cloning these ladders has been hell given their sheer number and the exact precision needed -- in addition to coming up with clear naming conventions to describe where ladders are and which ladders they clone. This is the first room encountered -- originally 0 ladders -- called "maproom":

https://steamcommunity.com/sharedfiles/filedetails/?id=1866524431

This room is fittingly just called "oneway":

https://steamcommunity.com/sharedfiles/filedetails/?id=1866524615

And this is "lastroom":

https://steamcommunity.com/sharedfiles/filedetails/?id=1866524772

What the heck are those orange, red, and yellow things you might be wondering? Here's a closer look:

https://steamcommunity.com/sharedfiles/filedetails/?id=1866524512

orange:

Valve wasn't very kind to Infected players with these ladders, not only making them annoyingly far away from the ledge but also placing func_breakable glass in the way of several of them. Valve did remove the glass on most sides of the ladders to assist with this and I just removed a couple more -- but when it came to "maproom" Valve didn't have ladders there before, so I created a tsu_breakable_killer function to Kill them by origin since that or trigger_multiples is the only possible ways to do that. I left Valve's glass on some of the low-traffic ladders to follow their artistic trend for asymmetry.

When it came to "lastroom", I didn't remove any of the glass on the side of the room Survivors run to the safe room... simply because I'm here to add new ladders and improve the experience with existing ones, not introduce new Smoker / Jockey setups. It's called Versus Ladder Rework, after all -- my focus is everything related to ladders and Infected navigation and some of those will inevitably produce (lots) of new attack opportunities but not when the Survivors have made it this far and deserve a safe breather.

(In all my func_breakable analysis I actually learned several railings have "minhealthdmg" less than 20 meaning Hunters etc. can scratch about ~5 very specific glass railings to break them whereas all others require a Charger or a Tank -- those were Valve oversights as they correspond to Coop-only dynamic escalators.)

red:

These are env_physics_blockers to artificially extend the ledge a bit. It was important to me that I didn't hand-hold the player, so I resisted the temptation to extend these clips all the way to the ladder instead stopping slightly short. This means that not every climb would succeed because it was still a little difficult, but still substantially easier.

I also didn't like the idea of Infected players "hovering" too much over an invisible ledge, so my extensions are modest. Implemented with tsu_physblocker_maker.

yellow:

These are trigger_push volumes at their smallest possible size to apply a "speed boost" to climbers. These were implemented with tsu_ladderpush_maker under very strict, very OCD guidelines:
  1. They can't over-baby the climber even still. These are intended as a very slight speed boost, just enough to propel the player diagonally toward the ledge just after a dismount just enough to (usually) land on the ledge.
  2. They're high up. Experienced players who dismount the earliest possible heights shouldn't touch the trigger at all. A player's un-ease with successfully climbing these ladders falls directly relative to how high they climb prior to a dismount -- so those more uneasy about it, will approach the trigger more often.
  3. They're high up... to exact measurements. It was vital that a Rocket Boomer jumping off the top-floors wouldn't hit the trigger to be propelled back onto the ledge. This is why some of the triggers are placed higher than others, because I'm also accounting for spots that still have glass. Jump heights were measured to exact precision and players will never trigger these jumping off the ledge or even jumping off a railing as those are exactly 38 units higher than all the others.
  4. They needed to be thin. Their Mins/Maxs are literally exactly the same. I'm surprised triggers work crazily well when they technically don't even have bounds.
  5. They're as close to the ladder as possible for the trigger to just barely work. I didn't want to place it them too far out (again interfering with a Rocket Boomer), or Hunters being confused about why they're seemingly being affected by a ladder that's so far away. The bottom-line is that if a player can trigger the pusher, they're definitely already mounted on it anyway.
  6. They're placed at the extreme sides of the ladder. It's necessary to have 2 triggers one for each direction, but also I didn't want climbers to unexpectedly get pushed mid-climb. So, they're placed with ridiculously stupid time-consuming precision so that they'll only take effect if the player is actually dismounting.
  7. A very niche bug was discovered that could only be 100% reproduced with a specific setup of having a trigger_push specifically setup to push the player away from the ladder, such that they'd instantly re-mount because they're kinda magnetic, upon which while still on that ladder the player will never be triggered by the push again -- until they dismount and climb it from scratch again. This bug still occurs with extreme rarity and could not be resolved with "spawnflags 257" which from Half-Life 2 "Affects Ladders", as that doesn't change anything in L4D2... it is unavoidable, but the push-direction and placement of the trigger reduces it to effective non-existence on top of it not being gamebreaking whatsoever.
  8. In effect, there's probably a way to Vscript complex code to "read the player's mind" to do this alternatively, but I've done the same thing with 8+ hours worth of precision testing and literally 1000's of climbs.

Overall, if players cannot ascend these ladders then they're deliberately setting out to fail at climbing them, but reasonable effort must still be made to climb them. Valve's other ladders in this map were implemented differently -- and better -- because they're angled. These jerks have always been (negligibly but audibly) hostile to player experience.

Sample Code

I used to be a big Stripper:Source buff, then became a _commentary.txt buff... but all those are dead to me when I've created several highly-optimized and efficient functions for each entity's creation that also outputs VERBOSE Debug data:

https://steamcommunity.com/sharedfiles/filedetails/?id=1866524881

What the heck would produce 8 pages worth of (entirely optional) console output?

This -- and this is a heavily-truncated summary mostly intent on showcasing careful naming convention that's only going to improve from here:

tsu_breakable_killer( Vector(3964.500000, ...), 10, true ); tsu_breakable_killer( Vector(4103.500000, ...), 10, true ); tsu_breakable_killer( Vector(4348.540039, ...), 10, true ); tsu_breakable_killer( Vector(4483.470215, ...), 10, true ); tsu_breakable_killer( Vector(4344.500000, ...), 10, true ); tsu_breakable_killer( Vector(4099.470215, ...), 10, true ); tsu_breakable_killer( Vector(2558.500000, ...), 10, true ); tsu_breakable_killer( Vector(-1400.500000, ...), 10, true ); tsu_breakable_killer( Vector(-1155.469971, ...), 10, true ); tsu_breakable_killer( Vector(-1016.500000, ...), 10, true ); tsu_breakable_killer( Vector(4487.500000, ...), 10, true ); tsu_physblocker_maker( "blocker_maproom_right", "SI Players", ... ); tsu_physblocker_maker( "blocker_maproom_left", "SI Players", ... ); tsu_physblocker_maker( "blocker_oneway_right", "SI Players", ... ); tsu_physblocker_maker( "blocker_oneway_left", "SI Players", ... ); tsu_physblocker_maker( "blocker_lastroom_right", "Everyone", ... ); tsu_physblocker_maker( "blocker_lastroom_left", "Everyone", ... ); tsu_ladder_maker( "ladder_maproomNW_cloned_onewaySW", Vector(1997.479980, ... ); tsu_ladder_facer( "ladder_maproomNW_cloned_onewaySW", "0 1 0", true ); tsu_ladder_maker( "ladder_maproomNE_cloned_onewayNW", Vector(1997.479980, ... ); tsu_ladder_facer( "ladder_maproomNE_cloned_onewayNW", "0 1 0", true ); tsu_ladder_maker( "ladder_maproomSW_cloned_onewaySE", Vector(2546.479980, ... ); tsu_ladder_facer( "ladder_maproomSW_cloned_onewaySE", "0 -1 0", true ); tsu_ladder_maker( "ladder_maproomSE_cloned_onewayNE", Vector(2546.479980, ... ); tsu_ladder_facer( "ladder_maproomSE_cloned_onewayNE", "0 -1 0", true ); tsu_ladder_maker( "ladder_scaffold_cloned_sodavent", Vector(754.000000, ... ); tsu_ladder_maker( "ladder_lastroomSE_cloned_lastroomNE", Vector(-1088.000000, ... ); tsu_ladder_facer( "ladder_lastroomSE_cloned_lastroomNE", "0 -1 0", true ); tsu_ladder_maker( "ladder_lastroomSW_cloned_lastroomNW", Vector(-1472.000000, ... ); tsu_ladder_facer( "ladder_lastroomSW_cloned_lastroomNW", "0 -1 0", true ); tsu_ladder_maker( "ladder_kappels_cloned_headroomvent", Vector(612.000000, ... ); tsu_ladder_facer( "ladder_kappels_cloned_headroomvent", "1 0 0", true ); tsu_ladder_maker( "ladder_bannerlower_cloned_sodavent", Vector(754.000000, ... ); tsu_ladder_facer( "ladder_bannerlower_cloned_sodavent", "-1 0 0", true ); tsu_ladder_maker( "ladder_bannerupper_cloned_sodavent", Vector(754.000000, ... ); tsu_ladder_facer( "ladder_bannerupper_cloned_sodavent", "-1 0 0", true ); tsu_ladderpush_maker( "ladderpush_lastroomNE_L",... tsu_ladderpush_maker( "ladderpush_lastroomNE_R",... tsu_ladderpush_maker( "ladderpush_lastroomNW_L",... tsu_ladderpush_maker( "ladderpush_lastroomNW_R",... tsu_ladderpush_maker( "ladderpush_lastroomSW_L",... tsu_ladderpush_maker( "ladderpush_lastroomSW_R",... tsu_ladderpush_maker( "ladderpush_lastroomSE_L",... tsu_ladderpush_maker( "ladderpush_lastroomSE_R",... tsu_ladderpush_maker( "ladderpush_onewayNW_L",... tsu_ladderpush_maker( "ladderpush_onewayNW_R",... tsu_ladderpush_maker( "ladderpush_onewayNE_L",... tsu_ladderpush_maker( "ladderpush_onewayNE_R",... tsu_ladderpush_maker( "ladderpush_onewaySW_L",... tsu_ladderpush_maker( "ladderpush_onewaySW_R",... tsu_ladderpush_maker( "ladderpush_onewaySE_L",... tsu_ladderpush_maker( "ladderpush_onewaySE_R",... tsu_ladderpush_maker( "ladderpush_maproomNE_L",... tsu_ladderpush_maker( "ladderpush_maproomNE_R",... tsu_ladderpush_maker( "ladderpush_maproomNW_L",... tsu_ladderpush_maker( "ladderpush_maproomNW_R",... tsu_ladderpush_maker( "ladderpush_maproomSW_L",... tsu_ladderpush_maker( "ladderpush_maproomSW_R",... tsu_ladderpush_maker( "ladderpush_maproomSE_L",... tsu_ladderpush_maker( "ladderpush_maproomSE_R",...

And skylight access?

https://steamcommunity.com/sharedfiles/filedetails/?id=1865385355

Yeah, working on that too -- the above code only includes the ladders for it so far, not all the extra props, and neither the rooftop re-surfacing. And if you're wondering about Vscript overhead or lag introduced by spawning all this stuff in... I've spammed it, and most human beings won't notice any delay. I sure don't.
Last edited by Tsuey; Sep 18, 2019 @ 11:37am
Tsuey Sep 21, 2019 @ 7:09am 
colorization? nty

If I had proper time management skills I never would've spent a night developing a crappy way to colorize Infected ladders:

https://steamcommunity.com/sharedfiles/filedetails/?id=1868871414

Disclaimer: Yeah I could just modify the texture file but my style is all server-side stuff!

The downsides are plentiful but the most obvious is the fact that Valve's default of "255 255 255" emphasizes the Green with the Red and Blue merely "fading" the Green, where "0 255 0" is the brightest possible Valve-colored ladder.

But as you tread away from Green, say with the extreme of a "255 0 255" Pink, it's readily evident that just 1 ladder texture isn't going to cut it (in the below screen, the left ladders are just 1 func_simpleladder, whereas the right ladders are 20 func_simpleladder stacked on top of each other):

https://steamcommunity.com/sharedfiles/filedetails/?id=1868871679

The Opacity / Alpha is already 255 -- it always is with ladders -- it's just that the Reds and Blues are extremely faint, and the only way to make Reds and Blues more opaque is by literally spawning 8-13 identical ladders on top of each other creating 100's of extra entities just to support a cosmetic purpose.

Not to mention the fact that with my current maker/facer functions this also breaks normals because I am using FindByName to set them which only modifies the 1st occurrence of an entity of the same-name whereas EntFire() would do all occurrences.

Needless to say this isn't realistic server-side -- though it is possible. And definitely a waste of time.

I wish I could even say that I've done everything there is to do with ladders, because while that's true for func_simpleladder, it's not yet completely true for the massive plethora of alternative ways to actually create ladders like func_useableladders of which I've investigated to varying extents throughout this Dev Thread though not as exhaustively. Regardless, ladder cloning is the only possible method for indistinguishable ladders.

on an semi-related note...

Here's a completely unremarkable screenshot of 3 new Infected ladders I added -- No Mercy 1 has over 20 new ladders by this point:

https://steamcommunity.com/sharedfiles/filedetails/?id=1867315299

I think that emphasizes the point that most of these ladders aren't going to be remarkable at all, because you may be confused that those are even new. There's ladders on the other side of the fence, but never the side depicted above... and as an added bit of trivia: the above 3 ladders all share (almost) the exact same coordinates because they're all rotated with respect to worldspawn origin.

The ladders people won't notice will end up being the best new ladders... and bringing attention to ladders by colorizing them? Well, at least I've thoroughly established that as a really bad idea enough to not think about it anymore.
Last edited by Tsuey; Sep 21, 2019 @ 7:15am
ESI Sep 21, 2019 @ 4:09pm 
Hey man. You don't know what Entity caused this messages:
Invalid counterterrorist spawnpoint at
Tsuey Sep 21, 2019 @ 7:47pm 
DEAD CENTER 2 HELP

Everyone wants new VS ladders but it has been extremely difficult to actually extract ideas from people because they (1) want so many or (2) see this as a simple Hammer endeavor when it sure as hell isn't close.

I profusely over-think everything, so even just having some other source backing up some idea helps solidify it from an idea to a measurable demand. These ladders need to be over-thought because of how long some of them take to add and L4D2 players deserve the best that is achievable damming the time expense -- and L4D1, I'm going to try supporting their game too because they're starved of new content (lacking Vscript, the only option there is _commentary.txt).

Two people were kind enough to lend me their eyes to tackle one of the largest, wide-open maps I've been dreading, which is Dead Center 2 -- which already has 77 Valve ladders but could benefit from 20++ more!

These are their full chat logs (always posted with permission):

✔ Hυѕку™
https://pastebin.com/ev1GkDY9

ᴿᴱᴻᴱ™
https://pastebin.com/F9HCrHsr

Within, there's also some random insights into why it's so difficult -- or in some cases, trivially simple if there's a nearby ladder of the correct angle and height nearby to clone and doesn't require a new pipe, func_playerinfected_clip, or func_illusionary (wrongway sign) etc. deletion. Most of the times, simple is not the case -- but at least Dead Center 2 offers the luxury of 77 default ladders to choose from (with which variety and options creates an overwhelming horror all the same)!

This is an example of the easiest ladder to clone: (1) Valve has already established the precedent on nearby vines to have a ladder, (2) their ladder is facing the same angle and is nearby, (3) it's also the same height, (4) it's not imbalanced because SI can already easily get up there so it's more just QoL, (5) it doesn't require a model because vines are already there, (6) there's no code necessary to remove func_playerinfected_clip / func_illusionary... overall, a ladder like this takes technically a minute to make:

https://steamcommunity.com/sharedfiles/filedetails/?id=1869211932

But then let's look at #@*&$#!'s like these, which are Valve's ladders, completely outside of the map, blocked off with func_playerinfected_clip which are easy enough to delete if it weren't for further assessing the prop_static wrongway signs which cannot be deleted:

https://steamcommunity.com/sharedfiles/filedetails/?id=1869218990

It's ladders like those that I'm going to assess every possible option and the final result is going to be the best one that's technologically possible.

And then there's open spaces outside of maps like this, where the wrongways are present but non-conflictory, there is a func_playerinfected_clip to delete, but there's also balance concerns to be conscious of since Tanks are frequently fought here:

https://steamcommunity.com/sharedfiles/filedetails/?id=1869228210

In general, anything that has vines already on the wall is a dead-giveaway for a ladder to be put there -- this one would add tremendous attack opportunity to a spot there was previously little / compensated with LOS blocker additions which would no longer be necessary:

https://steamcommunity.com/sharedfiles/filedetails/?id=1869225185

A ladder here is one of those "how is this not already a thing" types, and is a no-brainer:

https://steamcommunity.com/sharedfiles/filedetails/?id=1869551779

Ladders here should make Infected play a little smoother at this one-way:

https://steamcommunity.com/sharedfiles/filedetails/?id=1869551852

There always should've been a ladder here since forcing Infected to run around the hedge was design with minimal foresight:

https://steamcommunity.com/sharedfiles/filedetails/?id=1869551917

I'm sickly tired and need sleep BUT the point is, it's just so helpful to actually have requests, and at least 90% of their requests will be implemented exactly as desired and the rest in whatever similar-enough capacity is allowed.

When it comes to other campaigns, there's Dark Carnival Remix and Hard Rain Downpour to look at -- but Dead Center and No Mercy have been decided upon for initial release, so I'm only focusing on those until they're done.
Last edited by Tsuey; Sep 21, 2019 @ 7:50pm
Tsuey Sep 22, 2019 @ 4:31pm 
NO MERCY 3 GAS STATION && DESIGN DOC MANICISM

https://steamcommunity.com/sharedfiles/filedetails/?id=1870502609

What has always fundamentally sucked about the gas station? [artificial pause]

It doesn't alert a horde, and Survivors shoot it as soon as they can to take it out of play -- unless they're relying on luring or kiting a possible Tank there, which is a really fringe strategy.

I'm here to add ladders, not make mini-events... but there's no harm in injecting a strategic deterrent so the Survivors are slightly less compelled to destroy the gas station on-sight. The whole idea is that, if the Survivors destroy the gas station, it opens up an Infected ladder that gets them where they might want to be going, intentionally very slightly faster.

Before its explosion there's no good place to put an Infected ladder -- but after, there's at least options:

https://steamcommunity.com/sharedfiles/filedetails/?id=1870504610

The scissor lift event definitely needs more ladders, and the lazy imbalanced approach would be to place one here where the Boomer is (note, I'll most likely place one here anyway to make some people happy but it can be filtered out by specifying something like c8m3_POP_scissorlift_ladder where the POP stands for Potentially Over-Powered in vlr_blacklist.txt):

https://steamcommunity.com/sharedfiles/filedetails/?id=1870507050

Without a new ladder, this one that's so far away has always been the Infected team's only option:

https://steamcommunity.com/sharedfiles/filedetails/?id=1870508935

And the really annoying thing is that Valve already has 2 ladders out of the map here, which require Killing a func_brush wrongway sign, a func_playerinfected_clip, and only Zeus knows why a env_player_blocker:

https://steamcommunity.com/sharedfiles/filedetails/?id=1870509348

The manicism started when I realized that everything -- including the func_brush wrongways which are ordinarily implemented as still-deleteable func_illusionary -- could be deleted with code... because my inspiration here would've died if the wrongways were the dreaded prop_static.

THE MANICISM

NOTE: I'm not actually doing these steps, it's a lot more work -- but every new ladder set this "big on code" warrants a design document -- because this whole thing is going to execute 200-300 lines of code. Needless to say, I'm excited about this one.

STEP 1

Find the exact coordinates for the func_brush wrongway sign, func_playerinfected_clip, and env_player_blocker which I want to delete. Write functions for them. Check the map for exploits opened up by Killing these, and patch them with tsu_physblocker_maker.

https://steamcommunity.com/sharedfiles/filedetails/?id=1870522989

STEP 2

Find the best possible props to adjust m_flModelScale for to re-surface the NODRAW wall with the ladder with a single new prop. It should go without saying that Valve's 2 ladders will be kept, and the wall will be made to actually look official.

https://steamcommunity.com/sharedfiles/filedetails/?id=1870523370

STEP 3

Find the best possible ladder to clone to create a new ladder here that leads to the roof, that's always available for Infected to use, regardless of the gas station being blown up or not. This at the very least is subject to debate / testing, since someone might want the Infected players to be inconvenienced even more to have to climb over the fence and use one of Valve's ladders instead -- however, I'm opting to minimize inconvenience and place one here:

https://steamcommunity.com/sharedfiles/filedetails/?id=1870514731

STEP 4

Add 2 ladders with tsu_ladder_maker / tsu_ladder_facer:
  1. The gas station ladder will only spawn in when it's exploded. Yes, as all ladders are Vscripted anyway spawning them in whenever I want is child's play.
  2. Add a ladder to the higher rooftop. This is how Infected will primarily reach the lower rooftop (for the Charger off the scissor lift) without having to go really really far to Valve's solitary ladder. Possibly make use of the fire escape, too.

https://steamcommunity.com/sharedfiles/filedetails/?id=1870516451

STEP 5

It's a very nice thing that I don't have to resurface this massive rooftop -- thanks Valve!

https://steamcommunity.com/sharedfiles/filedetails/?id=1870518260

But I do need to create fake collision around the EASTERN WATERWORKS sign, otherwise Infected just walk right through it. Luckily, all other rooftop structures have collision.

STEP 6

Mindlessly stare at it for 2-3 hours to try and think of ways this sucks or can be broken. The vast majority of new ladders aren't this complex, but some sure will be, and that's why I'm so freaking slow.

It always sounds like a lot less work than it originally felt like once it's written down.

THE RESULT

Survivors now have some strategic deterrent to NOT blow up the gas station. Granted, it's an extremely small deterrent and the Infected still have newer, better options, even if they don't blow it up -- but the reality of the matter is that the way Survivors actually play the map will now actually have a direct affect on the ladders at the Infected team's disposal.

This doesn't harm anybody, and it sounds minor because it intentionally is.
Last edited by Tsuey; Sep 22, 2019 @ 4:37pm
Tsuey Sep 22, 2019 @ 5:07pm 
NO MERCY 3 GAS STATION ++ PSEUDOCODE

I did mention 200-300 lines of code -- factoring in brackets on single lines and debug code that's going to be skipped when it's shipped, that's not far off... but I did just want to quickly emphasize this level of simplicity:

tsu_wrongway_killer( "c8m3_Dyn_gasstation_MOD_killwrongway", Vector(coords) ) tsu_infectedclip_killer( "c8m3_Dyn_gasstation_MOD_killclip", Vector(coords) ) tsu_plyrblocker_killer( "c8m3_Dyn_gasstation_MOD_killplyrblkr, Vector(coords) ) tsu_physblocker_maker( "c8m3_Dyn_gasstation_physblocker", mins/maxs/etc. ) // To fix exploits I introduced tsu_resurface_maker( "c8m3_Dyn_gasstation_resurface", m_flModelScale, model path, etc. ) // Literally an over-sized door tsu_ladder_maker( "c8m3_Dyn_gasstationside_ladder_cloned_source", etc. ) // All source ladders un-determined tsu_ladder_maker( "c8m3_Dyn_gasstationdynamic_ladder_cloned_source", etc. ) tsu_ladder_maker( "c8m3_Dyn_gasstationhighroof_ladder_cloned_source", etc. ) tsu_dynamicprop_maker( "c8m3_Dyn_gasstation_prop_waterworks", model, etc. ) + logic_relay same-name piggyback to inject Valve's gas station I/O for ladder

Is what I'm going for. That's this entire thing.

The Dyn is the filtration category that indicates it's a dynamically spawned in ladder that doesn't exist at all times -- which will also be used for some intro/outro ladders to accommodate for escape vehicle paths. The _MOD_ makes it very clear for instances where I'm not spawning in new entities, but rather deleting what's already there (or various other cases of modifying what's already there like making a func_breakable immune) -- this String (even though it doesn't name an entity) is critical for vlr_blacklist.txt to filter out un-wanted changes by Versus Ladder Rework.

https://www.youtube.com/watch?v=LZiOQqz9PN0

Also, hey Rene :D! I hope this makes what I'm doing a little clearer.
Last edited by Tsuey; Sep 22, 2019 @ 5:12pm
Tsuey Sep 22, 2019 @ 5:29pm 
VLR CATEGORIES

Everything needs a name, like this:

c8m3_Dyn_gasstation_physblocker c#m#_Category_creation_class_<optional clone info etc.>

Categories can be safely completely ignored and specific things like "gasstation" which aren't categories can also be blacklisted; but categories exist as a way to quickly indicate stuff that's not wanted, that will go into vlr_blacklist.txt -- all functions will check the String this file was written into, and if any of these character sequences exist the function will return; and do nothing.

If a ladder matches multiple categories, I pick the "most offensively dominant". For example, Blood Harvest 5 barricade is a Fix (includes "z_finale_spawn_safety_range" tweaks as additional logic), is technically also an IOD meaning that the ladder it adds is deleted to accommodate the outro where the truck drives through it, but the Fix category takes massive precedence.

I'm constantly editing and tweaking this list -- but it gives a good example of the sheer variety of scenarios I'm coping with:

Box Ladder required Kill of massive clips w/ new blockers/WW to extend bounds Col Non-collidable props needed to be re-created in same spots with collision Dcl Infodecals used to justify ladders to Survivors will be lost on re-join Evt Event-based, of which alter Valve's narrative (Dead Center 1 shaft only) Fix Like Blood Harvest 5's barricade, these nerf desperate BS Survivor camps Gim Gimmicky, ladders that require adaptation and inquisitiveness to use IOD I/O dynamics spawned or Killed to accommodate for intro/outro cinematic Kil Valve ladders which are impossible to salvage and therefore just deleted LoS Line-of-sight blockers needed to be added to make not completely useless Mov Moved ladders, 100% unchanged otherwise (Dark Carnival 4 electrical box) OoB Out of bounds, these are distant from attacks and useless 99.9% of games POP Potentially over-powered, significantly alter Tank / critical attacks QoL Quality of Life, content 99.9% hardly notice & Valve will be told to add Ruf Re-surfaced rooftops, content requiring scaled door Vscript / clip Kills Svr Survivor perspective may be adversely impacted i.e. overtly-obvious props Tel Teleports, for anti-skyboxes, and will never allow tongues/vomit & cull WWd Wrong-wayed, passages through un-immersive non-deletable "wrongway signs" Zed Common Infected vaguely "appear" to "negotiate" these w/o updated navmesh

This is effectively my Bible for "classifying" whatever it is I'm working on -- the vast, vast majority of ladders will be either QoL (Quality of Life) or POP (Potentially Over-Powered) -- or Dcl (infodecals) for ladders which are outside of maps which even if the player were to rejoin or join late for the infodecal to be lost, it doesn't disrupt Survivor immersion anyway so it matters a whole lot less... Infected immersion matters, but by Valve's own standards not always, and I'm mimicking their standards.

Mov

And for a quick example of Mov, moving Valve's ladders, the dreaded:

https://steamcommunity.com/sharedfiles/filedetails/?id=1870558680

I've had some invaluable conversations with NF, and one thing I'll never forget is both him making me aware that this is a thing that I'll use for another project:

] help disable_static_prop_loading
"disable_static_prop_loading" = "0"
cheat
- If non-zero when a map loads, static props won't be loaded

In addition to him hating this ladder so bad that he even entertained the idea of just disabling all prop_statics server-side... then he opted to just create Dark Carnival Remix as any sane person would do! :D
Last edited by Tsuey; Sep 22, 2019 @ 5:46pm
Tsuey Oct 6, 2019 @ 3:04am 
_commentary.txt and the bane of L4D2 speedrunning

Dark Carnival tricks certainly have their way of finding me, first it was trash bins and now it's ruining L4D2 speedrunning because there's now a 50% chance your 1337 Dark Carnival 5 speedrun can lose ~15 seconds:

[1:53 AM]
Tsuey:
do speedrunners know that the left stadium chopper trigger has a 0.1 second window in which, if the last and only alive survivor is standing inside it when the chopper relay fires, ~15 seconds can be saved by standing inside the escape trigger in advance? "c2m5_concert_commentary.txt" is almost a tutorial on this... _commentary.txt's (by their nature) spawn in once and their states persist round transition... l4d2 in effect potentially has its own "zelda back in time" variant where if _commentary.txt-created relays aren't properly re-initialized manually with info_gamemode, their states and I/O will persist round transition... the _commentary.txt makes an effort to disable the escape trigger at 1.1 delay (whereas Valve's BSP delay for enabling it is 1 second), but it might be applicable to other relays

[1:54 AM]
Daroot Leafstorm:
lmao
yeah that wasn't known
god that's so stupid
I kind of don't want them to know because it's just a stupid way to lose time

There's good reason that speedrunners use unpatched versions of L4D2 because (though with growing infrequency) updates can happen anywhere and any time and it's not very fun to have strategies invalidated by Valve, Rayman1103, or in this case potentially -- myself. But not from fixing this bug -- as technically it's already fixed -- but rather because it creates a condition of RNG that L4D2 speedrunners will live on to hate forever.

And "c2m5_concert_commentary.txt" has been a tutorial on this exploit sitting under all our noses for a decade.

The birth of an exploit

The investigation started when Xanaguy brought a bug to my attention where -- on rare occasion -- the hordes would simply stop coming. He was on his own server at the time then noclipped out into the map to see where they were all congregating and immediately, I knew this to be (relatively) the final resting place of chopper left's info_goal_infected_chase:

https://steamcommunity.com/sharedfiles/filedetails/?id=1870488569

Of which along its path, the chopper ends up passing exactly the spot the commons end up uselessly congregating:

https://steamcommunity.com/sharedfiles/filedetails/?id=1870469166

I'll warn that why this happens exactly is still being investigated, so I'd surely benefit from any other's analysis in this regard -- but I'm here to discuss the one thing that is definite...

A _commentary.txt primer

Valve predominantly uses _commentary.txt files to patch L4D2 exploits, which given they're just *.txt files holds the benefit of limited bandwidth consumption.

Throughout this entire Dev Blog I've chronicled my difficulties in fully understanding the limitations (and strengths) of this sort of patching. There's a few very notable things about entities created by _commentary.txt files:
  1. They only spawn in once, ever. This means that the same entity is used for both rounds of VS, or all death-restarts of a Coop run. Usually this is just a lowly env_player_blocker, but in possibly-exploitable cases could be a logic_relay.
  2. Their last known state will persist the round transition. If an info_gamemode isn't also updated to re-initialize _commentary.txt-spawned entities, their entity definition containing StartDisabled 1 is useless because that was only in effect after the 1st time it spawned.
  3. Their I/O will persist the round transition...

c2m5_concert_commentary.txt

I'm not sure about heavily-unpatched versions of L4D2, but currently everybody's up-to-date L4D2 has this data, in that file -- note that I'm pretty sure this is in all the heavily-unpatched versions, because if it wasn't this exploit would be drastically more apparent and would've been found already:

"entity" { "classname" "info_gamemode" "angles" "0 0 0" connections { "OnCoop" "stadium_exit_left_physicsblockerDisable1-1" "OnScavenge" "stadium_exit_left_physicsblockerDisable1-1" "OnSurvival" "stadium_exit_left_physicsblockerDisable1-1" "OnVersus" "stadium_exit_left_physicsblockerDisable1-1" } "origin" "-1136 2664 -208" "mapupdate" "1" } "entity" { "classname" "logic_relay" "spawnflags" "0" "StartDisabled" "1" "targetname" "stadium_exit_left_relay" connections { "OnTrigger" "stadium_exit_left_physicsblockerEnable17-1" "OnTrigger" "stadium_exit_leftt_escape_triggerDisable1.1-1" "OnTrigger" "stadium_exit_leftt_escape_triggerEnable17-1" } "origin" "-1136 2664 -240" "mapupdate" "1" }

What you're looking at above is stadium_exit_left_relay is a same-name piggyback that's the same name of Valve's own BSP relay, but adds more I/O instructions to the game since the existing BSP relay will indiscriminately take on its new I/O with the old. This is how logic is patched into the game without the addition of triggers.

In this case, the patcher went to great lengths to re-initialize stadium_exit_left_physicsblocker knowing their Enabled states would persist the round -- but never Disables the relay... of which, actually isn't a problem in this case which I'll explain as I go.. but it's still wrong, and there's other problems.

And this is a portion from Valve's BSP[raw.githubusercontent.com]:

{ "id" "511022" "origin" "-1136 2664 -240" "targetname" "stadium_exit_left_relay" "StartDisabled" "1" "spawnflags" "0" "classname" "logic_relay" connections { "OnTrigger" "stadium_exit_left_navblockerUnblockNav1-1" "OnSpawn" "stadium_exit_left_navblockerBlockNav1-1" "OnTrigger" "stadium_exit_leftt_escape_triggerEnable1-1" } }

Do you see the exploit window? I'll show you:

_commentary.txt:

"OnTrigger" "stadium_exit_leftt_escape_triggerDisable1.1-1"
"OnTrigger" "stadium_exit_leftt_escape_triggerEnable17-1"

Valve's BSP:

"OnTrigger" "stadium_exit_leftt_escape_triggerEnable1-1"

This file is basically a tutorial on exposing the fact that Valve by default Enables this left chopper escape trigger at 1 second delay:

https://steamcommunity.com/sharedfiles/filedetails/?id=1882130313

The _commentary.txt was updated to re-Disable it at 1.1 second delay, then finally Enable it at the normal 17 second delay. There is a 0.1 second exploit window upon which the escape animation sequence can be skipped.

And the worst part of it? This is only for the left chopper!!!

The right chopper doesn't have this oversight.

I'm very sorry!

The reproduction steps

Open L4D2

Open console > sv_cheats 1 > map c2m5_concert coop

warp_all_survivors_to_finale

nb_delete_all so you're the only Survivor, and director_stop

Start both finale buttons

Teleport yourself here:

https://steamcommunity.com/sharedfiles/filedetails/?id=1882178400

setpos_exact -1133.218872 2666.701660 -27.968750;setang_exact 13.778687 167.344421 0.000000

And then stand there -- there's only an exploit window of 0.1 seconds

Spam ent_fire trigger_finale advancefinalestate with kick tank at the ready

Viola, now we can all hate this finale even more:

https://steamcommunity.com/sharedfiles/filedetails/?id=1882169476

Hypothetical :: Zelda Back in Time L4D2 variant

WARNING: This is just hypothetical here on out, the trick portion of this post is over.

I'll be investigating the other _commentary.txt files over the short-term future, but let's say that if the _commentary.txt didn't Disable at 1.1 delay, what we'd essentially have is this:
  1. Players start Dark Carnival 5 and make their way through the finale.
  2. With plenty seconds of leeway, all Survivors died the moment the finale ended and the left chopper started to arrive
  3. As that _commentary.txt-created relay has a 17 second delay, its I/O would persist to the next try
  4. Thus ~15 seconds into that next try, the escape trigger will have been activated allowing for instant escape

To elaborate a bit: while the _commentary.txt relay specifies StartDisabled 1, as it's a _commentary.txt entity it's never actually Enabled or Disabled until the chopper is chosen:

"targetname" "stadium_exit_whichside_case" "classname" "logic_case" connections { "OnCase01" "stadium_exit_right_relayDisable0-1" "OnCase01" "stadium_exit_left_relayEnable0-1" "OnCase02" "stadium_exit_left_relayDisable0-1"

So while its Enabled state can effortlessly be forced to persist, its Triggered state obviously cannot be. To add: I haven't been very clear on the fact that ordinary BSP entities are respawned on round transition, in fact No Mercy 4's func_elevator is respawned on round transition as if it were a normal player -- however, _commentary.txt entities do NOT work this way, and only exist once forever.

This would only ever be vaguely useful for generously-segmented runs as you would've already have had to complete the finale to be able to die then insta-complete it -- but dependent on how other _commentary.txt relays and delays are laid out, this could actually have useful applications elsewhere.

That, has yet to be confirmed.
Last edited by Tsuey; Oct 6, 2019 @ 5:31am
Tsuey Oct 7, 2019 @ 2:47pm 
Random nav nuisances

To quickly vent, No Mercy 1's breakwall, where Survivor bots always have to go the long way around even if the wall is broken:

https://steamcommunity.com/sharedfiles/filedetails/?id=1879797757

It's sloppy stuff like that which makes people make fun of this game. The countless bots that have been slaughtered in VS due to them making this useless journey.

m30w Oct 3 @ 7:43pm
pour out a drink for all the bots that have died in vs games going around the other way

Anyway, Sharples reminded me to look into hordes spawning on top of you in the Blood Harvest 3 and Cold Stream 2 safe rooms, and updated NAV files would serve the game well on those maps and others.

Rayman1103 submitted an updated NAV file for Death Toll 5 and we'll see how that pans out, the additions (and the easy BH3 / CS2 causes) detailed in here:

Gameplay problems
https://steamcommunity.com/app/550/discussions/0/1631916887505878858/

Once that's added, I'll be aggressively documenting more NAV fixes... because starting out, I never thought updated NAV files were an option for us. We'll see.
Last edited by Tsuey; Oct 7, 2019 @ 2:49pm
ESI Oct 7, 2019 @ 3:27pm 
Originally posted by Tsuey:
Random nav nuisances

To quickly vent, No Mercy 1's breakwall, where Survivor bots always have to go the long way around even if the wall is broken:

https://steamcommunity.com/sharedfiles/filedetails/?id=1879797757

It's sloppy stuff like that which makes people make fun of this game. The countless bots that have been slaughtered in VS due to them making this useless journey.

m30w Oct 3 @ 7:43pm
pour out a drink for all the bots that have died in vs games going around the other way

Anyway, Sharples reminded me to look into hordes spawning on top of you in the Blood Harvest 3 and Cold Stream 2 safe rooms, and updated NAV files would serve the game well on those maps and others.

Rayman1103 submitted an updated NAV file for Death Toll 5 and we'll see how that pans out, the additions (and the easy BH3 / CS2 causes) detailed in here:

Gameplay problems
https://steamcommunity.com/app/550/discussions/0/1631916887505878858/

Once that's added, I'll be aggressively documenting more NAV fixes... because starting out, I never thought updated NAV files were an option for us. We'll see.
Where download fixed Navigation Mesh file for map ?
Last edited by ESI; Oct 7, 2019 @ 3:27pm
< >
Showing 121-135 of 153 comments
Per page: 1530 50

Date Posted: May 5, 2019 @ 6:15am
Posts: 153