Back in 2016, I was idly going through HL2’s source code and started tweeting interesting tidbits; this interested people a lot and PC Gamer made an article out of it. Twitter’s dying a weird death, so I’m gonna put those tweets here now, and maybe elaborate on some of it. Come with me now on a journey through 20-year-old C++.
Good to know Valve and I pretty much have the same comments in our AI!
This was almost literally true; I was working on a stealth game at the time that had a comment like this. This is in HL2’s zombie AI; it wanders randomly when it loses track of its enemy because the alternative would be just standing there. AI is about pretending to be smart, not being smart (something I learned on my stealth game after oversimulating a ton of stuff that looked worse than much dumber behaviour).
Hey cool. Never realised fastzombies never pounce if you aren’t looking.
Fast zombies have a big screaming leap-at-your-face thing they do; you run away because of it, and it can’t happen while you’re running away. A lot of stuff in HL2 has code to only happen if you’re looking. I wrote a post sort of about that concept, it’s a strat I always took for granted maybe because of my Valve-modding background and was later surprised to see sort of rarely deployed (at the places I’ve worked, anyway).
Ah, the ol bunch of checks to hopefully maybe catch a bad thing happening eventually ending in “dunno”
This is the fastzombie again, printing to the console if he gets stuck and has no enemy. My comment sounds snarky but it wasn’t, that’s just life baby
Nothin mindblowing here but I’m gonna keep posting this stuff bc I find it interesting
It is interesting!
A strider can’t shoot down your rocket if it wasn’t already firing when you fired the rocket?
This is a trend I’m not into in HL2’s code – the game sort of bending over backwards to manufacture a player-competence narrative (which I see as quite distinct from just “making the game easy”). I talked a bit about this stuff in my video Laments On Half-Life 2’s AI And Balance, which I stand by, although it doesn’t acknowledge actively enough that getting this stuff right is just very difficult. There’ll be a lot of stuff like this. After I made that video I did get to talk to some HL2 devs about it who thought it was a good video, so that was nice.
Striders deliberately vary their targets up to look cool/not win too easy
I always think stuff like this is missing from most people’s NPC targeting code; “just keep firing at the thing you’re trying to kill” is probably not what most folks’ll do in a shootout scenario. I think I did a post somewhere about how “accuracy” should be an attribute of a character and not a gun; I should dig that up.
Can anyone confirm whether striders can skewer with their right leg, because I bet this never got fixed
Unconfirmed. I still bet that.
Strider might still shoot if it knows it won’t hit ya if there’s something there it’d be cool to hit
My comment makes it sound like this is about shooting other objects purely for dramatic effect, when it’s actually about shooting the player through stuff. The strider might still have that hit-on-miss behaviour though – it does exist on other NPCs, and especially the sniper.
Huh, what’s that look like
It looks like a big sparky your-legs-fall-off death. Surprised I didn’t remember that. “Inflictor” is an interesting terminology here; the Unreal equivalent is “Damage Causer” (as distinct from Instigator, which would be the person shooting as opposed to the bullet). Actually not sure which Inflictor is here.
There’s a thing in HL2 it doesn’t give you the opportunity to notice where Scanners can report your loc to striders
I actually wrote a post about this (originally in reply to someone on Cohost) so you can read that if you want.
I never knew this, but apparently if you get enough rollermines stuck to your car they all explode?
The reason I didn’t know this is because that code is commented out, which I didn’t notice for some reason. I turned it back on and liked it, but it was pretty mean. I guess since this would be happening on the coast levels, there’d be times that it would mean almost certain death for a hapless low-health player with nowhere to get enough health to survive it.
Just rollermines jolting the car
I wonder why those zap effects got commented out. Tempted to try flippin’ ’em back on.
Rollermines auto-embed in the ground if a dropship drops ’em. I didn’t even know a dropship could drop ’em.
Unusually verbose comment block
This is cool, a shame there aren’t really mobs of zombies in HL2.
I remember thinking a lot when Left 4 Dead 1 came out, with its amazing zombie locomotion and everything, about whether that would mean, for Episode 3 (lmao), a new approach to HL2’s NPC nav and locomotion. An actual horde of headcrab zombies would be cool to see, as would just… soldiers being able to step up onto a knee-high platform.
Cool little comment about rebalancing zombies after some changes to the shotgun happened.
It’s kind of interesting to see this; the shotgun was changed to be way more powerful and so the zombies got special-cased to ignore that change. Maybe the extra damage was to make it feel good against soldiers? Nothing worse than a weak shotgun.
Code determining whether a zombie should drop his headcrab when he dies.
Headcrabs surviving a zombie death must have been exciting to get to do. Big scare the first time it happened as a player, I bet, if you hadn’t watched the E3 teasers a billion times.
HL2 zombies on fire only take damage from that fire/take less damage from most weapons so they don’t die real quick
I wonder if not reducing buckshot damage here is because it was already reduced above.
Aw, poor little things
I gotta look into the Actbusy Tool sometime. Seems like it’s for semi-scripted leans on walls and junk
I never did check out the actbusy tool.
That’s an interesting way to determine that. 10% of health in burn damage has to be done to ignite a zombie.
I think I thought this was interesting because the more damaged the zombie was the more flammable it would be, but if so I didn’t read it right; it checks the zombie’s max health, not its current health. Still, this isn’t what I usually see done, which is more of a flat rate for time-spent-in-fire to ignite; but then I also wouldn’t tend to implement this on the NPC but on a generic “flammable” component that the NPC gets one of. Zombies aren’t the only NPC that can ignite, so maybe this lives in the NPC base class, not sure.
Interesting! On spawn, zombies (presumably) magically know where you are for a bit?
This is presumably for when a zombie gets spawned at runtime, mainly? I wouldn’t think you’d want this for zombies placed in the level.
Lastly I’m gonna take a look at item_dynamic_resupply which I had a big rant about recently
These are the supply crates in HL2; they don’t decide what’s in them until they break. I have a beef with them. They were a last-minute balancing addition in response to realising the game’s maps had mostly been playtested piecemeal and balanced based on that, so they each played great on their own but could fall apart as part of an actual playthrough. So these crates were introduced to try to dynamically solve balancing without manual intervention, and they were supposed to be tweaked per-map, but mostly weren’t, so they flatten the difficulty out pretty hard, always giving the player whatever they’re low on. I think it’s a better game if you just delete them (which you can do with a script: ent_remove item_dynamic_resupply
on map start. Most of the manually-placed items that predate the crates were never removed from the levels.
If you don’t need anything, crates just contain health or the first ammo-thing on a list, or don’t spawn at all.
PVS = PotentiallyVisibleSet; the surrounding area. So, crates take into account what items are already nearby. System works too well, though. Never any scarcity of anything in HL2. Good system if it was only on/this effective on easy mode.
PVS was a really convenient structure that resulted from Source being a Quake-derived BSP engine; things like this you’d have to approach differently on Source 2 since you presumably don’t get a PVS in the same way anymore.
Crates never spawn ammo you don’t have the gun for, etc.
This is functionally probably a good thing, but it does rule out the potentially intriguing experience of picking up bullets for a gun you’ve never seen. Or it would, if the crates were the only way to get ammo.
Feel validated, everyone!
Part of HL2’s explosion code with comments.
Often when I’ve worked on someone else’s project in Unreal they’ve got explosions re-implemented separately on everything that creates one – eg, check for damageable objects, check LOS, deal damage with falloff, do a particle effect, etc. Even before I was really thinking systemically this always bothered me, I think because of some innate sense that HL must not have done it that way, so I always make an ExplosionManager that anything can call into to create an explosion in a generic way. Weird West had this and it definitely made us more free-and-easy with explosions.
On the interface for choosing chapters in HL2, points for “zany”
HL2 barnacle code. The tragedy of eternal FIXMEs
Kidding of course, eternal FIXMEs rule. Of course, this is a physics thing, so maybe it got fixed from somewhere else.
Didn’t realise barnacles die on-eat-something-poisonous, cool. Not sure on distinction between black/poison headcrab
Not realising this until I found the code didn’t stop me being a stickler about it when Half-Life: Alyx didn’t keep this behaviour, and hassling a Valve friend about it. They had no idea either, but there’s a scary part this behaviour would have ruined, so fair play anyway.
Respect to Valve for having only one “fuck” in the entire HL2 codebase.
This is from HL1, but a great comment. (yes I’m searching bad words)
One reason why the Source Engine shared-engine-updates-between-multiple-games-years-apart model is maybe a bad move.
This is a banger tale I’m glad I found. I always thought it was wild how much havoc was wrought by keeping older games on the latest version of the engine, but they never stopped doin’ it.
Reading between the lines, the level-breaking strider damage bug was probably in for a year before they found (not fixed) it. Whoooops. This is one of about a million things that broke in HL2 around 2005-2007, some of which were never fixed, the rest of which took years. Another reason is how frequently stuff like this broke mods, mostly never to be fixed. The Mac HL1 update also broke many HL1 mod
It’s years later now, and most of these issues have been corrected in the HL1 and HL2 anniversary updates!
HL2’s “low violence” mode = no blood, insta-fade-out ragdolls. It ditches the fade-out, though, for the citadel maps
“Low violence” mode just cutting out for the game’s finale was always funny to me. I guess the classification boards don’t play all the way through! This is the same system that L4D2 launched with in Australia when it was refused classification.
For a second I was like “oh no, my doors don’t check for pawns on auto-close”, then realised “oh mine don’t autoclose at all”.
This is a nice improvement on HL1’s autoclose, which, if I remember right, would just happen anyway and bounce off you (or, depending on the door, crush you). These check first.
This is potentially useful stuff for anyone’s doors, though.
These sorts of events are super useful if you have a level scripting tool that can hook into them, which HL2 does. I have a video or massive blog post in me waiting to happen someday about the benefits of a simplified input/output based level scripting paradigm over Blueprint (or anything that expects level designers to write actual code).
HL2 suit power exploit saveguards.
The most bizarre decision in HL2 is surely to tie the flashlight battery and sprint battery together, and then tie that also to the oxygen used when swimming such that if you go down a dark hallway with your flashlight on and leap into water you now can’t breathe because you used all your breath on the flashlight. It’s interesting that they have some sort of actual Device System going on here though – seems more elaborate than I would have thought for what it is.
Ah, good bit of HL2 Ep1 commenting (kind of thing they’d put in the dev commentary). On Alyx/barnacles in the dark
This is a cool edge case catch. Light actually mattering to an NPC is such an unusual thing, I really enjoyed this part of Ep1.
Here’s an interesting one: Combine Advisor AI. Never gets used in the shipped games. Sounds like fighting a grav gun
Fighting advisors in (presumably?) Ep3 sounds cool. Catching and throwing back phys objs is the best thing in HL2DM.
More classic Half-Life “only do the cool thing when the player is looking” stuff.
Advice for life
This is interesting!
The concept of “weapon proficiency” in HL2 is an interesting one; it feels sort of superfluous to what the game ended up being, but maybe I’m misunderstanding it. The HL2_SINGLE_PRIMARY_WEAPON_MODE
thing here does work if you set it to 1; it goes to a “Halo style” weapon system where you can only carry two at a time. This goes to pieces in HL2 of course because there are two weapons (crowbar and gravity gun) that you absolutely need, plus grenades. I made a mod (unreleased) that enabled this and added dedicated buttons for melee (quick crowbar swing) and grenade (quick throw), but the gravity gun really stops the Halo approach from working well. You can see this was enabled when the E3 Traptown video was recorded, though; the player throws a gun away to pick up another one.
Not code comments, but here’s something rarely-before-seen: the Source Particle Benchmark Demo! ~2006. (this was never publically released but also not leaked; I knew someone who emailed Gabe and just asked for and was given it)
More interesting, though, is that Valve left in npc_surface, a prototype of the fluid stuff that ended up in Portal2
It’s trying to take the shape of the Hydra (cut from HL2), but is missing the model it needs
:O
This is interesting. From HL2’s ai_basenpc class. Instead of just taking a shot and missing, looks for the most interesting miss
Ever since I read this I do it everywhere. Such a simple thing to do that adds so much drama in any gunfire situation.
Opening doors is hard
Greatly to HL2’s credit that you don’t often see somebody stuck in a door. Nightmare stuff.
Interesting thing about this comment is it’s circa ~2003 or earlier so the TF2 mentioned isn’t one any of us have played
Shortly after this I chatted with someone who worked on this TF2, which had aliens and vehicles; I asked why it was cancelled. Wasn’t coming together? Nah, it was great, he says; we just all got pulled off it to work on HL2 and had to start over by the time we came back. Bummer!
“NPC picks up weapon” code like I implemented the other day. Is it just me or would this make AI always switch weps if not pistol or same?
This is something I use as an example sometimes when talking about not oversimulating: citizens pick up a gun if they see one on the ground that isn’t the same one they have and isn’t a pistol. Whether the new gun is better-suited to the situation than the old gun or not isn’t important; this behaviour just has to look smart, not be wise, and simply not doing it never looks smart. If someone ditches a shotgun for an SMG we can just infer that the character prefers it!
Hmm. On NPC death, “Drop enough ammo to kill 2 of me”. If not, fill up the gun w/ ammo before drop. I agree with neither of these decisions
This is another one I think is destructive to the experience. Scarcity is important! You never sneak around scared hoping to find ammo or health in HL2 the way you did in HL1, the horror vibe went out of it. I would sooner enable this stuff contextually if the player has been in a dire state for a long time, something like what L4D’s “AI Director” does with tracking “stress” per-player.
The other interesting thing here is they add some kind of extra effect to the dropped weapon if the game is running on the original Xbox, presumably because that was low-res as hell and likely to be running on a CRT TV. Cool.
Fix for an issue in Episode 1 where you could apparently throw the gravity gun out of the world in the upgrade scene
Hey smart
Hmm, this is cheating because the AI only throws the grenade if the player is actually there, rather than relying on soldier’s experience
Something else I don’t like – the soldier cheats here and doesn’t misdirect a grenade if the player is far from where he “thinks” they are. Just removes the cool experience of seeing that happen.
This was another I flipped for my “try to make the AI feel better” mod – I reckon if you can do a cool little player-acknowledgement gesture you might as well.
So many comments. One of em’s timestamped, makes me wish they all were
Onya sjb
This is good stuff but all the work that went into combine soldier speech might as well have not been done bc their speech is unintelligible
I think having these guys speak in code and highly-radio-filtered was a big error. The expressiveness of the soldiers in HL1 was huge for that game.
Good stuff about checking if combine soldiers should do a grenade throw, and a bug that never got fixed
Interesting comment re: hack for having too much RPG ammo in Follow Freeman if you spawn out of the chapter select screen w/ default equip
I think this is all the code comments I tweeted, but I’m not sure, because twitter’s so broken that I suspect a lot have been orphaned. This seems like plenty to be going on with, though!
Leave a Reply