Everyone knows how to fix the rotfish kill count bug in QuakeC. Today we’re not even going to bother, with a hack we can get correct kill counts in unfixed id1 Quake! For style points, we’ll add a way to do it without needing to add an entity.
Start by creating some
monster_fish in your map. Give them a
fish_fix and a
use key of
f_stand1. Normally, you can’t give monsters a
use function because the walk/fly/swimmonster start function overrides the map value with
monster_use. The trick today is that we’re intentionally skipping
swimmonster_start_go because that’s the function with the bug, and the way we’re going to do it is to run our
use function first.
To get in first, add a point entity and give it
classname DelayThink. Add a
target key of
fish_fix. This entity triggers its target the moment that it spawns, which will immediately run the
use function on all of the fish which have spawned so far. As long as all of the fish in the map are higher in the spawn order than the
DelayThink entity, the hack will run on all of them. We’ll improve on this later.
Try out the hack so far, and observe that the monster count is now correct! You’ll also notice that the fish are not behaving themselves – they don’t turn to face you, and they move in strange ways. Most importantly, they are immune to damage, so you still can’t get 100% kills! It turns out that
swimmonster_start_go did some important stuff, which we need to add back in. Luckily the important parts can be replicated by adding the following keys:
"takedamage" "2" "yaw_speed" "10" "flags" "34" "view_ofs" "0 0 10" "pausetime" "99999999"
The one big flaw with these fish is that they remain without the correct
use function, so you can’t trigger them later to wake them. I think fixing the kill count is well worth it.
The annoying part of this hack is making sure that the
DelayThink runs after all the fish spawn. If you add more fish to your map later on they might still be bugged. There isn’t a very large window to hit in order to reliably execute this hack, but there is one way of doing it which doesn’t rely on entity order. Delete the
DelayThink entity and add the following keys to worldspawn(!)
"nextthink" "0.05" "think" "SUB_UseTargets" "target" "fish_fix"
Amazingly, the world counts as an entity, and you can run a think function on it. Because you can’t ever modify the world without crashing, it’s impossible to do from QuakeC, but if the world is born with a
think function it will run.
SUB_UseTargets is one of the few safe choices of think function to use like this, because it doesn’t modify
self at any point. The nice thing about using the worldspawn like this is that it’s always first in the entity list, so it will always run at exactly the right time: after all the entities have spawned, but before any of them had a chance to think.
That’s it for today, but I see lots of unexploited potential in this hack. For example, we use the normal standing animation for a fish to interrupt the normal spawn sequence, but there might be other options which open up further possibilities. We put the fish’s fields back to their normal values, but we’ve actually gained the ability to hack these fields into non-standard behaviour. And that’s before we consider the idea of applying it to other monsters…