-
Notifications
You must be signed in to change notification settings - Fork 41
The Zombie Invasion
With bonzAI picking its own harvest rooms now, it was time to deal with the case where a potential harvest room is already inhabited. I already have code for a more decisive raid where tower damage is healed even at close range, rather than trying to drain the tower. In quite a few cases, these players will be inactive, a.k.a. "zombies", who won't put up much of a fight. I thought it worthwhile to try to write code that better scales to this situation.
This is the room I used as a test-case and also the type of situation I wanted to be able to handle with this code:
ZombieOperation.ts link
My solution was to fight fire with fire and code some zombies of my own. These creeps will be slow and stupid. The pseudocode in a nutshell:
if health is above threshold
approach nearest spawn in enemy room
ignore most structures while pathing, attack any structures in the way
if health is below threshold
approach fallback position
I also wanted tower-draining behavior to emerge from this pattern, having the creep utilize the exit mechanic to assist with healing. When a creep is standing an exit, it is in the room only every other tick, effectively halving the damage received. So I added this to the creep logic:
if standing on the exit for the enemy room, wait for at least 10 consecutive ticks with full health before stepping into the room
Tower damage is graded by distance, certain exits will be preferable above others based on their average distance to towers in the room. My solution was to look at every exit in the room and figure out how much damage it would receive, and picking the lowest one. I'd ensure my zombies would use this exit by blocking off all the other exits in the CostMatrix
.
Here is my first attempt to construct such a matrix:
let exitPositions: RoomPosition[] = [];
for (let x = 0; x < 50; x ++) {
for (let y = 0; y < 50; y++) {
if (x !== 0 && y !== 0 && x !== 49 && y !== 49) { continue; }
if (Game.map.getTerrainAt(x, y, this.room.name) === "wall") { continue; }
exitPositions.push(new RoomPosition(x, y, this.room.name));
matrix.set(x, y, 0xff);
}
}
let bestExit = _(exitPositions)
.sortBy((p: RoomPosition) => -_.sum(towers, (t: Structure) => p.getRangeTo(t)))
.head();
matrix.set(bestExit.x, bestExit.y, 1);
Here is the room that I am using for testing: