">
← All posts

Bots carry their ammunition

Bots reloaded out of thin air. Every reload simply set the magazine back to full.

That had been recorded as a deferred decision rather than a design, which is a useful distinction to keep: it marks the difference between "this is how it works" and "we have not decided yet, and here is the one place to change when we do."

One set of rules

Bots now carry a real inventory (four spare magazines plus the loaded one) and reload through the same code a player does. A bot that fires enough is empty, and stays empty until it finds more.

That single change produces three behaviours without any of them needing to be written separately.

Bots ration. When low on ammunition they stop suppressing fire, the deliberately-not-meant-to-land fire that keeps your head down. Aimed fire is never rationed, because a bot that can see you and refuses to shoot does not read as tactical. It reads as broken.

Bots scavenge. A dry bot walks to a body and loots it. Dead bots leave real corpses holding exactly what they had: remaining magazines, the rounds still in the weapon, the weapon itself, the plate, the helmet. It is the same corpse list players fill, so players loot bots and bots loot players through one code path.

Bots upgrade. A better weapon, plate, helmet, or an earpiece if they have none, leaving the old item on the body rather than deleting it. Nothing evaporates from the raid because a bot decided it preferred something else.

Corpses had to start expiring

This forced a change that was not in the plan.

The corpse list was push-only, and it is hashed in full every tick as part of the determinism guarantee. With bots respawning on a timer, tick cost grew with total deaths over the whole raid rather than with bodies currently lying around. A long raid gets slower forever.

Only empty bot bodies are swept. A body still holding something is a promise to whoever watched it fall. You saw where it dropped, you should be able to go and get it. And a player's body is never swept at all, because it is the entire stake of their raid.

Two bugs the tests caught

The pistol outranked the rifle. The function scoring weapons used damage per round. The pistol does 18 against the rifle's 14, the single statistic the pistol wins. Bots would have cheerfully swapped rifles for sidearms and counted it an upgrade. It scores damage per tick of sustained fire now, which is the thing that actually matters in a fight.

Extraction was counting ammunition as cash. The value-carried calculation included magazine round-counts, so extracting with three full magazines reported 90 more than the player was actually carrying. That one had shipped in the previous commit.

On the test count

The golden determinism hashes moved here, deliberately: there are new hashed fields, new corpses in the recorded run, and genuinely different behaviour now that a dry bot stops firing.

One note for anyone reading the suite output. The quick check script reports around 172 tests because it stops at the first failure. The real number is 1029 passing, 3 failing, and all three of those fail identically on the parent commit, so they are pre-existing rather than caused here. Two extraction failures that were mine are fixed in this change.

A test count that stops early is not a small truth. It is a wrong one, and it had been quietly making the suite look a sixth of its real size.