Zombies spawned from a new spawn point at one of the entrances to Concord. Why add extra spawns? There are many mods out there that sp...

Zombies spawned from a new spawn point at one of the entrances to Concord.

Why add extra spawns?

There are many mods out there that spawn actors in the game and some of them spawn extra Feral Ghouls that work with Zombie Walkers. The trouble is they tend to spawn creatures only in certain areas as is the case with the Zombie Apocalypse mod or spawn so frequently that they create an arcade-like experience.

I wanted a dynamic approach that would spawn not just in cities but also the country-side. Also, I wanted respawns to happen in a way that would flow with playing the game as if zombies wandered into the area in your absence.

Many players have asked for more zombies and while the spawn replacement changes have largely answered this, it still leaves areas of the game world empty once cleared when playing on survival. I wanted the outdoors to continually re-populate over time and keep players looking over their shoulders.

Where to spawn?

The first challenge is determining where to spawn zombies. Here are a few thoughts I had while working on this:

My first thought was to pick a location at a random distance from the player, but this would quickly lead to zombies spawning in places they shouldn't like inside buildings or water. 

I then started thinking about spawning them where creatures have already spawned. The trouble is I was unable to get a reference to the leveled creature markers via script. For a bit I considered spawning my own hidden spawn marker whenever a creature replacement was processed. The trouble with this is that it relied on replacements being enabled and would add extra markers to keep track of (not to mention slightly increasing save game size).

Then I started researching markers that already existed in the game and which ones I could dynamically query for via script. During testing, I spawned vertibird grenades or pre-war shiny cars at these markers so that I can see where they were. There are several types available, but two in particular stood out and were chosen for the first version: 
    1. Patrol Markers - 8,972 in base game
    2. Center on Cell (COC) Markers - 622 in base game
Center on Cell Marker at one of the entrances to Concord.

How to spawn?

In my experiments with spawn locations, I noticed that Patrol markers in particular are sometimes clustered in groups as many as 10-15. I didn't want to have 10-15 separate spawn points for what is essentially one area, so I needed a way to tag just one of them as a spawn point but the others as not. To do this I created two keywords: ZombieSpawn and SkipZombieSpawn.

I already have a script attached to a hidden quest that I use for replacements, so I was able to use that and simply add more aliases to it. The first alias was for "potential zombie spawn points" and the second was for checking if existing "zombie spawn points" should spawn.

The potential spawn markers are filled by any Patrol or COC markers in the load area around the player that have not been processed (has neither of the keywords). For each potential spawn point, I check the area around it for an already existing spawn point (within a certain distance). If there is already a spawn point nearby, then I add the SkipZombieSpawn keyword, otherwise I add the ZombieSpawn keyword which effectively turns that marker into a new zombie spawn point. Note that markers located in settlements, cities, or interior cells are excluded from becoming spawn points.

The existing zombie spawn points are filled by anything in the load area around the player that has the ZombieSpawn keyword. For each spawn point, some processing is done to check if this spawn point should spawn and if so zombies are spawned at that marker's location.

When to spawn?

Determining when to spawn was a little more tricky and may be an area that I revisit with some tweaks as this new feature is play tested. 

The first thing I added was a time constraint. The game has the concept of game days passed which you can get by calling Utility.GetCurrentGameTime(). Each spawn marker has an actor value added to store a timestamp in the future that signifies when this spawn marker is eligible to spawn. Basically I take the current value of game days passed and add to it.
  • Get current game days passed 
  • Add 2 - 10 days to it (configurable via holotape)
  • Make sure time is midnight so zombies spawn at night 
I made the time midnight to avoid mid-day spawns as I'm assuming most players sleep at night. If you happen to be out and about at midnight, you might be in for a few surprises as you wander around. "I thought I just cleared this area?"

Once a spawn point is eligible to spawn, it will start to fill in the zombie spawns quest alias where the timestamp is checked:

Zombie Spawn Point quest alias match conditions.
 The next step is to do a couple extra checks to impose limits on the spawning and hopefully avoid problems:
  • Zombies may not spawn within 3000 units of the player
  • A configurable max zombies threshold is checked before spawning to avoid too many zombies spawning within a given area (currently 10,000 units radius of spawn point)
  • Also, note earlier that spawn points are not allowed to be created in settlements, cities, or interior cells.

Future Plans

In the short term, I'll be interested to hear player feedback on the feature to see if I need to make any changes. There are configuration items for max spawns in an area and the maximum number of days between spawns for a given spawn point. I may expand on these configuration fields moving forward.

Another thought I had has to do with an escalating zombie epidemic. Maybe I could add an optional mode where spawns slowly increase in size and frequency as time passes in the game?

Zombies are attacking Sanctuary! Refactoring is an ongoing effort with Zombie Walkers and this time I have revisited settlement attacks ...

Zombies are attacking Sanctuary!
Refactoring is an ongoing effort with Zombie Walkers and this time I have revisited settlement attacks once again. Settlements are a cool addition to Fallout 4 and lend themselves to the zombie apocalypse play-through as survival havens. As such, I want to make defending them actually matter.

What was wrong?

The first implementation used the game's built-in settlement attack quests. These are unfortunately a bit buggy due to the nature of all the code involved. Also, I feel a bit out of control in that I fire it off and sort of hope it works. I've had more than one user report being notified that an attack was happening and then not seeing any zombies. Others have reported setting settlement attacks to 100% and then never having their settlement attacked. Neither of these are acceptable.

A new approach

The settlement attack quests have a lot of logic involved in determining whether an attack should occur and where. In my mod, I just want to add extra attacks against the settlement you are currently at and the how often is a simple percentage checked hourly. Zombies now attack even if you have 0 food, water, and settlers.

To execute the attack, I use a quest alias to get a settlements LocationEdgeMarkers just like the game's built-in settlement attack quests. For the zombie attacks, I randomly choose one side to attack from only as zombies aren't smart enough to coordinate multiple attack vectors. The number of zombies that spawn is now controllable via a holotape option (from 10 to 30). Note that I've chosen to always spawn a minimum of 10 and the default max is 20.

Once spawned, the zombies are given a reference alias to the settlement's workshop (also bound via quest alias) so they path toward it. This workshop alias is a much simpler way to get a reference to the currently location's workshop than what I was doing which I'm not going to go into here.

I have chosen to retain the "Zombies are attacking ..." message to notify you of the attack but no longer have a message indicating the attack is over. This is due to not keeping track of the attacking zombies which the game built-in quest was doing. I didn't think it was necessary anyway. 

Another side effect of this new approach is what happens if you run away from the attack. In the games built-in quest your settlement structures can become damaged and possibly settlers killed. In this new approach, the zombies will eventually congregate around the workshop if you have no settlers. Having settlers may result in a long battle that the settlers will eventually win unless you have 'Kill Protected' enabled.

More than just zombies

The old implementation actually disabled settlement attacks from anything other than zombies since I was tying into the game's built-in quests and it was the only way to be sure a zombie attack happened when I wanted it to.

Now that I am executing the attack myself, I was able to restore the game's built-in settlement attack functionality so you can be attacked by raiders/super mutants/etc. again. I guess in theory you could be attacked by raiders and zombies at the same time, though it would probably be pretty rare.

A couple things to note though:
  1. the settlement attack holotape options only affects zombie attacks (frequency/max size)
  2. the replacement holotape options may still replace certain settlement attackers

Sanctuary Hills bug

One of the spawn points in Sanctuary was not working properly. It is the one near the main bridge that is actually located up in a tree off the ground (don't ask me why). Whenever this spawn point was chosen either zombies didn't spawn at all or they spawned in the nearby house near the bridge (the one not completely destroyed). To fix this, I moved the spawn point (via script) to the other end of the main Sanctuary bridge where I thought it belonged anyway.

Sanctuary Hills LocationEdgeMarker up in a tree that was moved to the other end of the bridge.

Future ideas

I'm already thinking about possible future enhancements. One thought revolves around putting a real negative consequence to abandoning your settlement during an attack. Maybe all your settlers die, the zombies stick around, and you lose control of the settlement until you clear the zombies and re-activate the workshop?

Level 8 Zombies approach the player in the woods. I initially set out to do some refactoring and re-introduce Fog Ghouls to the commonwe...

Level 8 Zombies approach the player in the woods.
I initially set out to do some refactoring and re-introduce Fog Ghouls to the commonwealth after deprecating the Far Harbor plugin to Zombie Walkers. I ended up reworking the entire zombie leveling scheme hopefully for the better.

The Old Way

The old zombie leveling scheme basically matched the game's built in approach for Feral Ghouls. There are eight (8) main base types of Feral Ghouls each at a different level with different stats. These 8 types are combined in leveled list and the version that spawns is highest level Feral Ghoul that is at or under the player's current level. Below is a table of the main stats I'll be focusing on:

Level XP Damage Resist Energy Resist Base Damage* Health
1 - 8710203035
9 - 141315304570
15 - 212230456080
22 - 3132406070140
32 - 4147507580170
42 - 5161609095200
52 - 617670110105385
62+9085140120505+

*note: Base Damage was increased by 15 over base game and extra radiation damage removed. The value listed is damage done on Normal difficulty (2x = very hard, 4x = survival).

A couple things to note from the above:

  • Health increases greatly at level 52 and again at level 62. After 62, the zombie health can and does continue to grow as the level 62 variant of Feral Ghoul is the only one that levels with the player.
  • Base Damage on survival is lethal. At level 1, zombies do 30 * 4 = 120 damage which is enough to one shot many characters. Survival is the difficulty this mod is meant to be played at, but zombies one shotting players isn't what I am going for either.
  • Between level jumps, the zombie stats remain static. This means a level 8 zombie is identical to a level 3.

The New Way

I used the Google Chart API to graph the progression of these statistic changes for Feral Ghouls and noticed that most fit a linear trend. The API allows charts to render trend-lines that provide the formulas which I extracted and used in the OnInit method of the zombie's script to set there stats after they spawn. Here are screenshots of the charts (just in case the API changes, I don't want to have to maintain them here):

XP = 1.432 * Level + 1.063
Damage Resist = 1.24 * Level + 8.276
Energy Resist = 1.933 * Level + 13.988
Damage =  1.433 * Level + 33.175
Health = 5 * Level + 20
A quick note about the Health chart. Notice the two red dots above the trend line toward the right. Feral Ghouls gain more health at levels 52 and 62 than they normally do prior to that. It seems like an attempt by the game creators to just make them a lot tougher for high level characters to face. To create this trendline, I basically used the 35 health at level 3 as a base and extrapolated it out using the game's known health leveling formula. Coincidentally, all of the other Health totals fell in line with this trend.

Survival Damage Adjustment

The new way actually increases damage dealt at level 1 to about 35. On survival this becomes 140! To address this, I added a new holotape option that allows players to adjust the amount of damage done on survival and set the default to match very hard (2x) so that level 1 damage is 70 which should be survivable (at least 1 hit anyway).

To implement this so that it only affects zombies, I actually divide the damage they do by an amount to where when it is multiplied by 4 (survival's damage mult) it comes out to the value I want. For example: diving 35 by 2 gives 17.5, which when multiplied by 4 becomes 70.

Refactoring Spawn Variety

To initially implement spawn variety, I created copies of the 8 actor types for each level increment and manually adjusted their stats at each level. Tedious, painful, and a maintenance nightmare. Not to mention having 8 * 8 = 64 zombie actors increased the size of the mod.

To refactor, I deleted all the extras and stuck with the base 8 types. All of their stats are set via a script attached to them when they spawn now, so I no longer have to worry about manually setting their stats via the GUI. 

I also went through and added all available skin tones for Feral Ghouls in the base game to all variations (Traits -> Object Template on the Actor in CK) and added the special Pink zombies from Suffolk County Charter School for fun.

  4 different base outfits (default, bloody, withered, armored)
* 7 different base skins (Carrion, Charr, Dark, Green, Grey, Pale, Pink)
= 28 base combinations
+ 1 special Suffolk Country Charter School skin/outfit
+ 1 Fog Ghoul skin/outfit (if Far Harbor installed, see below)
= 30 total combinations

Fog Ghouls Zombies

Finally, I added the necessary code to add the Fog Zombies to the commonwealth if you have Far Harbor installed. Originally, I was just going to add the outfit to the list above, but I thought it would be funner and maybe more appropriate to use these zombies to replace marine creatures (if spawn replacements are used). In this way, when you enter an area that would spawn things like Mirelurks, which are normally near water, you would start to see the fishing net covered Fog Zombies.

Here's the list of creature types replaced by Fog Zombies (if replacements are enabled):
  • Creatures
    • Anglers
    • Gulpers
    • Mirelurks
  • Heavy Knockers
    • Fog Crawlers
    • Hermit Crabs

Zombie Walkers 2.0

The above was released as part of the Zombie Walkers 2.0 release. Since the leveling changes and refactoring was quite large and affected the core of the mod, I decided to finally up the major version number. I'm hoping to stick with a more canonical versioning scheme moving forward.

Other changes included in this release was a fix for immortal zombies caused by explosive damage and a reset of the Far Harbor leveled lists to help those migrating away from that deprecated mod.

A Zombie Horde approaches! In almost every tradition zombie film the zombies tend to horde together in groups and wander around. This is...

A Zombie Horde approaches!
In almost every tradition zombie film the zombies tend to horde together in groups and wander around. This is something I've always wanted to bring to my mod and I've finally gotten around to implementing it.

AI Packages

Packages are sets of instructions that influence the behavior of actors in the game. You can think of them as configurable AI that gives actors (like zombies) a list of possible actions to perform.

Many actors in the game, including Feral Ghouls, have default packages assigned. One in particular has a lot of useful functionality already called the Default Master Package which I'll talk about below.

Linked References

Step one is figuring out how to make them move. It really isn't a horde if the zombies just stand around. What I wanted to accomplish was zombies that walk around aimlessly if they are idle (not in combat).

This is where the aforementioned packages come in. The Default Master Package has procedures for Follow and Patrol. Both of these procedures work by making the actor path to a linked reference. A linked reference can be just about anything and there are methods in Papyrus to GetLinkedRef and SetLinkedRef.

Patrol (aka. make them wander)

The patrol package is triggered if a zombie has a linked ref set to something like an Idle_Marker. Idle Markers are hidden objects that mark a particular location or object. They can be explicitly assigned as a linked reference to an actor or idle actors can "discover" them on their own if they happen to be in the area (like settlement workshops).

In my case, I spawn an Idle Marker in a random direction away from a zombie I want to make walk and then assign the marker as the zombie's linked reference. This is enough to make the zombie slowly walk (regardless of the Speed setting on the holotape).

Once they get to the marker, they stand around. Of course I want them to continue wandering aimlessly until they bump into something (ie. enter combat). To do this, I use the RegisterForDistanceLessThanEvent between the zombie and the Idle Marker. This event triggers when the zombie gets within a certain radius I define of the marker. When it triggers, I simply move the marker. This pattern repeats and the zombie continues to follow the continuously moving marker.

The direction they move is random at first and then they generally stay in the same general direction afterward. I assigned a number to the basic cardinal directions and used an Actor Value assigned to the marker to keep track of the direction. The first move is completely random, then the subsequent moves can be straight ahead (no change) or 1 value deviation from the last direction.

7 (NW)0 (N)1 (NE)
6 (W)2 (E)
5 (SW)4 (S)3 (SE)

Dealing With Patrol Problems

Unfortunately, there are times when a zombie is unable to reach the Idle Marker or at least get close enough to trigger the DistanceLessThan event. In those cases, the zombie will just stand around and stop moving so we need to do something about it.

I created another Actor Value for timestamp and assigned it to the marker to keep track of the last modified time. This timestamp is set when the marker is created and any time it is moved.

I already have a hidden quest with a trigger to do some processing every 10 seconds or so. I updated this function to add a check for all markers (of a type that I spawned). If a marker's timestamp is older than some threshold I define then the marker is deleted and I send a Custom Event.

All zombies that are spawned listen for my custom ZombieMarkerDeleted event that is generated by my quest's script and respond to it. In the case of a zombie that is wandering, it begins the wandering process all over again by spawning a brand new marker in a random direction.

From Wandering Zombies to a Horde

OK, so at this point we have every zombie wandering in it's own direction randomly. To make it a horde they really need to band together some how and move in groups.

To accomplish this, I took advantage of the Follow procedure which works similar to the Patrol above. If you set a linked reference for a zombie to another zombie then it will follow it. It's really that simple.

But wait, who should follow who? I came up with a simple solution to allow the zombies to determine whether to follow or start patrolling themselves. The zombie effect script that gets attached to them (see Dynamic Script Attachment) now sets their FeralGhoulFaction rank randomly from 0 to 100 and that rank is used to determine who follows who.

  • Check for nearby zombies and follow the first one you come across with a higher rank than my own.
  • If no zombies are nearby with a higher rank, then start to patrol (wander by spawning an Idle Marker to path to). 
  • Note that any zombies that have decided to follow me will therefor also start to patrol behind me.

Dealing With Follow Problems

The only real problem you run into when following another zombie is what to do if that zombie dies. The easy solution for this is to register for the OnDying event and follow someone else (or start to patrol ourselves).

Issues With Quests

After release, a bug was reported where a player was sent to clear zombies from an area but when they got there the zombies were nowhere to be found. As you might have guessed, the horde behavior caused them to wander out of the area before the player got there.

To address this and avoid interrupting quests, I decided to disable the horde behavior for certain zombies so that they would be there when expected. To determine which zombies to not move, I ended up discovering by some research that many of the quest related actors in the game are linked to their location with a Location Ref Type. There types allow quests to quickly determine if all actors in a group are still alive (eg. functions like GetRefTypeAliveCount). You can check if any actor is used as a Location Ref Type pretty easily using GetLocRefTypes.

Another exclusion I ended up adding is for zombies that spawn in a Clearable or Dungeon location. These locations often rely on the actors being present to be "cleared" and can easily be checked by GetCurrentLocation and HasKeyword.
  • do NOT follow or patrol if:
    • Actor (or replacement) has a least one linked Location Ref Type
    • Actor (or replacement) spawned in a Clearable or Dungeon location.
The "or replacement" refers to the optional Spawn Replacements holotape settings. If used, the replacement is taken into account in determining mobility. Note that if replacement levels larger than one for one (eg. two for one) are used, then the "extra" zombies are not tied to the original actor in any way and can and will wander freely.

Wrap Up

The combination of patrolling and following described in this article gives zombies an initial wandering horde behavior that is much preferred over just standing around. It adds a dynamic unpredictability to every play-through as well in that you'll never know where zombies might appear even if you've memorized all the spawn points.

I'll likely continue tweaking this behavior as bugs are reported and ideas come to me. I already have thoughts about adding additional marker types for noise and possible dead bodies. Noise markers could serve to attract zombies from farther away than the game's default detection range (but not make them hostile, just make them lumber toward the sounds in the distance). Dead bodies could attract nearby zombies for a feast as Idle Markers can have Idle Animations associated with them (eg. the Feral Ghoul crouching and eating animations).

Infinite zombies spawning to replace molerats at the Rotten Landfill location. Sometimes, too many zombies is a bad thing. Like when sai...

Infinite zombies spawning to replace molerats at the Rotten Landfill location.
Sometimes, too many zombies is a bad thing. Like when said zombie horde crashes your game. This is unfortunately what was happening at the Rotten Landfill thanks to how the quest there worked in conjunction with animal spawn replacements.

The Issue

There is a quest used at the Rotten Landfill to stage a fight between a settler and some molerats. The idea is to have this fight continue until the player is close enough to witness it and potentially intervene.

The quest marks the settler as immortal and spawns a few molerats that are marked to re-spawn when killed. When the player gets within 6000 units the fight is triggered and will continue forever with the molerats continuously re-spawning as the immortal settler eventually kills them. When the player gets within 3000 units the fight becomes real in that the settler is mortal and the infinite re-spawns are stopped (and instead become X waves as described on the wiki).

When using the animal spawn replacement option via the Zombie Walkers holotape, these molerats are replaced by zombies. During that replacement, the molerat being replaced isn't just disabled (disappearing from view) but also killed. Since the molerat is killed, it triggers the quest to re-spawn the molerat which in turn gets killed and replaced with a zombie. This triggers the molerat to re-spawn again... well, you probably see where this infinite loop is going.

Why kill the replacement?

Good question. I knew some quests involve creatures that might be replaced by my mod. To avoid those quests getting stuck, I wanted to make sure they didn't end up waiting for a death event that would never arrive. The first example of this I can think of is the Sanctuary bloatfly quest with Codsworth.

So how do we fix Rotten Landfill?

The easy solution would have been to simply exclude the location from spawn replacements, but I'm too masochistic for that. Instead what I ended up doing is delaying the kill until the zombie that replaced the molerat was killed.

This was actually fairly straightforward to implement. At time of replacement, the creature being replaced is still disabled and I added a linked reference to the creature being replaced to the zombie that was replacing it with a new keyword. When that zombie died, I added code to check for that type of child linked ref and kill it also if present. Note that this only applies to the first zombie replacing that actor, so if you are using 2 for 1 replacements, the second zombie's death will do nothing to the replaced actor.

This approach not only solves the Rotten Landfill issue but also keeps quests from getting stuck. It should also be universally applicable for other re-spawns that might be used in other areas. Finally, it makes sense and flows better while you are playing the game. Now when you meet Codsworth in Sanctuary, you will search the neighborhood killing zombies instead of bloatflies instead of the quest starting out in a "I already searched the neighborhood" state.

Immortal Zombie (reaver armor) with the gunshot wounds to the head to prove it. Zombies That Magically Heal Sometimes zombies just do...

Immortal Zombie (reaver armor) with the gunshot wounds to the head to prove it.

Zombies That Magically Heal

Sometimes zombies just don't want to die, even when you shoot them in the head numerous times. In the case of the Reaver style zombies (encFeralGhoul04), they get knocked down and then get back up with full health restored. This is the zombie type I've personally noticed this bug with and it is 100% repeatable with them. All other zombie variants die as expected with a headshot.

Tracking Down the Issue

Tracking this down involved a lot of trial and error, but eventually it came down to what I believe to be a bug in the game with Deferred Kill and this particular Feral Ghoul actor type. Deferred Kill basically makes it so an actor does not die until you tell it to. If headshots only mode is enabled, then deferred kill is started when the zombie is initialized.

To end the deferred kill, I registerd for the OnCripple event. This event is triggered when any limb (including the head) is crippled by damage. I noticed for the Reaver style armored zombies that this event was triggering twice and that the deferred kill seemed to not be honored.
Event OnCripple(ActorValue akActorValue, bool abCrippled) 
[ZombieEffectScript] HandleCrippleEvent([Actor < (FF00134A)>],[ActorValue <PerceptionCondition (0000036C)>],True) -> 0.000000
[ZombieEffectScript] HandleCrippleEvent([Actor < (FF00134A)>],[ActorValue <PerceptionCondition (0000036C)>],False) -> 100.000000
 As you can see above, the first call has 'True' for the crippled bool flag for the PerceptionCondition (head) which is good. In that handler I EndDeferredKill and then call Kill if the actor is still alive. This apparently isn't good enough for the Reaver zombies as they regenerated their health and limbs, did NOT end deferred kill and got back up off the ground. This regeneration is what I think triggers the second onCripple event which notifies the code that the head is now un-crippled (abCripple is 'False').

After some experimenting in game, I noticed that you could in fact kill these zombies if you shot it multiple times in the head in succession (while it was dropping to the ground). I then experimented with shooting them in the torso a bit first and then the head which revealed a pretty consistent way to dispatch them as they died almost always with a single head shot if their health was down a bit first.

Fixing the Problem

As an experiment, I updated my onCripple handler to remove any remaining health before ending the deferred kill state and that fixed the issue. Apparently triggering EndDeferredKill when their remaining health was 0 always worked for the Reavers, even though the other types didn't care how much health was remaining. I think it wasn't the EndDeferredKill call itself so much as the subsequent call to Kill that seemed to behave differently.

Here's what I ended up with:
; helper function to handle both onCripple and onPartialCripple
Function HandleCrippleEvent(Actor akSender, ActorValue akActorValue, bool abCrippled)
Debug.OpenUserLog("joefor")
Debug.TraceUser("joefor", "[ZombieEffectScript] HandleCrippleEvent(" + akSender + "," + akActorValue+ "," + abCrippled + ") -> " + akSender.GetValue(akActorValue))
If( abCrippled )
If( akActorValue == HeadConditionAV )
; head is crippled - make sure zombie dies
KillZombie()
Else
; other body part crippled - apply knockdown
ZombieActor.PushActorAway(ZombieActor, 1)
NPCFeralGhoulInjuredDownNotOutEnter.Play(ZombieActor)
EndIf
EndIf
EndFunction
Function KillZombie()
float healthAmount = ZombieActor.GetValue(HealthAV)
Debug.OpenUserLog("joefor")
Debug.TraceUser("joefor", "[ZombieEffectScript] KillZombie(" + ZombieActor + ", health=" + healthAmount)
; there's a bug with Feral Ghoul 04 not dying if health remains before deferred kill ends
; make sure remaining health is zero to trigger deferred kill
ZombieActor.DamageValue( HealthAV, healthAmount )
; end deferred kill to allow zombie to die
ZombieActor.EndDeferredKill()
; now, make sure zombie dies
If( !ZombieActor.IsDead() )
ZombieActor.Kill()
EndIf
EndFunction 

Version 1.15 Coming Soon

I'm wrapping up some testing and will be deploying in the next day or so. Here's what will be included:

  • The fix described above for immortal zombies
  • fix for Suffolk County Charter School (humans in underwear spawning instead of zombies)
  • NEW optional horde behavior - zombies follow each other and wander around instead of standing still where they spawned (I may blog separately about this)

Update 1/1/2017: more immortal zombies

More immortal zombies, one of which is missing half its skull.
Another immortal zombie bug was reported and has been fixed. This one has to do with situations where the OnCripple event is not received by the script and therefore the zombie never leaves the deferred kill state. Subsequent OnCripple events are not received for the head if you continue to shoot the head.

To reproduce this, I used a missile launcher and aimed for the chest in a group of zombies. The immense amount of damage seems to sometimes cause this. I'm still not 100% sure why the OnCripple for the head (PerceptionCondition) is not received by the script. I noticed that every time it happens, the script does receive OnCripple for the body (EnduranceCondition). Maybe the game assumes if the torso is crippled (which is rare) then the creature will die anyway so it doesn't bother sending a separate one for the head?

In either case, to fix the problem I added one more event registration to the script. This one is for the OnDeferredKill event. This event gets triggered when an actor is in the deferred kill state and receives damage that would kill it if it weren't in that state. It also happens to fire over and over again as damage is received, even if the health goes into the negatives. Basically, I use this function to check the state of the head and end deferred kill if it is destroyed.

Let's hope this is the last of the stubborn zombies that refuse to die.

Update 1/27/2017: crippled vs dismembered

Even after my last update, still some immortal zombies were reported albeit rarely and usually when using certain explosive weapons like Spray N' Pray. Upon further research I noticed that in VATS only their torso was target-able as in the screenshot below.

Immortal zombie with only the torso target-able in VATS.
I began doing research into what would cause the head to not be there and quickly realized that it is actually dismembered (like the legs/arms in the screenshot above). After adding some debug logging I then saw that sometimes the head health would be above zero even though the head was dismembered!
OnDeferredKill([Actor < (FF000F36)>],[Actor < (00000014)>]),  PerceptionCondition = 20.053139, HeadDismembered = True
I then updated my function to check if the head is destroyed by checking EITHER:

  • Head health is 0 (PerceptionCondition)  ... OR ...
  • Head is dismembered (Head1 for feral ghouls and humans)
I then tested by spawning groups of 20-30 zombies at a time, waiting a bit for my scripts to attach and initialize on all of them, and then mowing them down with Spray N' Pray. Before the changes I was seeing 1 or 2 in every group in the immortal state in the screenshot above. After the change I could not produce a single occurrence even after spawning several waves.