test: cover tests.gameCaptureAtRemovesTheCaughtMonsterFromTheLevelWit...
This commit is contained in:
1 parent
fce4742c18
commit
6f260eb25f
1 file changed
+173
+173
@@ -12239,6 +12239,179 @@ function tests.captivesResolveCatchesABatteredTargetIntoACaptiveAndZeroesItsHp()
|
|||||||
eq(captive.value, Monsters.xpFor(rat), "the captive's value matches Captives.valueOf")
|
eq(captive.value, Monsters.xpFor(rat), "the captive's value matches Captives.valueOf")
|
||||||
eq(rat.hp, 0, "the caught monster's hp is zeroed")
|
eq(rat.hp, 0, "the caught monster's hp is zeroed")
|
||||||
ok(not rat:isAlive(), "the caught monster is no longer alive")
|
ok(not rat:isAlive(), "the caught monster is no longer alive")
|
||||||
|
ok(contains(lines[1], "bound"), "the log reports the net dropping true")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameCaptureAtRemovesTheCaughtMonsterFromTheLevelWithoutAwardingAKill()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 3, 6)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 6, 1)
|
||||||
|
rat.hp = 1
|
||||||
|
game.level.entities = { rat }
|
||||||
|
local before = #game.player.inventory
|
||||||
|
game.player.inventory[#game.player.inventory + 1] = Items.net()
|
||||||
|
local index = #game.player.inventory
|
||||||
|
game.rng = Rng.new(2)
|
||||||
|
local xpBefore = game.player.xp
|
||||||
|
local killsBefore = game.stats.kills
|
||||||
|
local success = game:captureAt(index, rat)
|
||||||
|
eq(success, true, "a successful net capture reports the item as thrown")
|
||||||
|
eq(#game.player.inventory, before, "the net leaves the inventory once thrown")
|
||||||
|
eq(#game.level.entities, 0, "the captured monster is swept from the level's entities")
|
||||||
|
eq(#game.level.captives, 1, "the captured monster becomes exactly one level captive")
|
||||||
|
eq(game.player.xp, xpBefore, "a capture grants no xp")
|
||||||
|
eq(game.stats.kills, killsBefore, "a capture is never counted as a kill")
|
||||||
|
eq(#game.level.corpses, 0, "a captured monster leaves no corpse behind")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameCaptureAtLeavesTheTargetAliveAndTheNetUnspentWhenOutOfRange()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 2, 2)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 19, 9, 1)
|
||||||
|
rat.hp = 1
|
||||||
|
game.level.entities = { rat }
|
||||||
|
game.player.inventory[#game.player.inventory + 1] = Items.net()
|
||||||
|
local index = #game.player.inventory
|
||||||
|
local before = #game.player.inventory
|
||||||
|
local success = game:captureAt(index, rat)
|
||||||
|
eq(success, false, "a capture attempt beyond range fails")
|
||||||
|
eq(#game.player.inventory, before, "a failed capture attempt does not consume the net")
|
||||||
|
ok(rat:isAlive(), "a failed capture attempt leaves the target alive")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameRansomCaptiveWarmsFactionStandingWithNoGoldChange()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
game.level.captives = { { x = 5, y = 5, species = "rat", faction = Factions.VERMIN, name = "rat", value = 3 } }
|
||||||
|
local goldBefore = game.player.gold
|
||||||
|
local repBefore = Factions.reputationFor(game.player, Factions.VERMIN)
|
||||||
|
local success = game:ransomCaptive()
|
||||||
|
eq(success, true, "ransoming a held captive succeeds")
|
||||||
|
eq(#game.level.captives, 0, "ransoming removes the captive from the level")
|
||||||
|
eq(game.player.gold, goldBefore, "ransoming changes no gold")
|
||||||
|
eq(Factions.reputationFor(game.player, Factions.VERMIN), repBefore + Captives.RANSOM_REP_GAIN,
|
||||||
|
"ransoming warms the captive's own faction standing")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameSellCaptivePaysGoldAndCoolsFactionStanding()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
game.level.captives = { { x = 5, y = 5, species = "rat", faction = Factions.VERMIN, name = "rat", value = 7 } }
|
||||||
|
local goldBefore = game.player.gold
|
||||||
|
local repBefore = Factions.reputationFor(game.player, Factions.VERMIN)
|
||||||
|
local success = game:sellCaptive()
|
||||||
|
eq(success, true, "selling a held captive succeeds")
|
||||||
|
eq(#game.level.captives, 0, "selling removes the captive from the level")
|
||||||
|
eq(game.player.gold, goldBefore + 7, "selling pays exactly the captive's own value in gold")
|
||||||
|
eq(Factions.reputationFor(game.player, Factions.VERMIN), repBefore - Captives.SELL_REP_LOSS,
|
||||||
|
"selling cools the captive's own faction standing")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameInterrogateCaptiveRevealsEveryHiddenDoorAndGrantsEssence()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
game.level.secretDoors = {
|
||||||
|
{ x = 8, y = 8, discovered = false },
|
||||||
|
{ x = 9, y = 9, discovered = false },
|
||||||
|
{ x = 10, y = 10, discovered = true },
|
||||||
|
}
|
||||||
|
game.level.captives = { { x = 5, y = 5, species = "rat", faction = Factions.VERMIN, name = "rat", value = 8 } }
|
||||||
|
local essenceBefore = game.player.essence
|
||||||
|
local success = game:interrogateCaptive()
|
||||||
|
eq(success, true, "interrogating a held captive succeeds")
|
||||||
|
eq(#game.level.captives, 0, "interrogating removes the captive from the level")
|
||||||
|
ok(game.level.secretDoors[1].discovered, "interrogating reveals a previously hidden door")
|
||||||
|
ok(game.level.secretDoors[2].discovered, "interrogating reveals every previously hidden door, not just one")
|
||||||
|
eq(game.player.essence, essenceBefore + 4, "interrogating grants essence equal to half the captive's value")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.captiveFieldsSurviveALevelSerializationRoundTrip()
|
||||||
|
local level = arena(21, 11)
|
||||||
|
level.captives = { { x = 5, y = 5, species = "rat", faction = Factions.VERMIN, name = "rat", value = 3 } }
|
||||||
|
local restored = Level.fromData(level:toData())
|
||||||
|
eq(#restored.captives, 1, "a held captive survives a level round trip")
|
||||||
|
eq(restored.captives[1].name, "rat", "the captive's name survives a round trip")
|
||||||
|
eq(restored.captives[1].faction, Factions.VERMIN, "the captive's faction survives a round trip")
|
||||||
|
eq(restored.captives[1].value, 3, "the captive's value survives a round trip")
|
||||||
|
eq(restored:captiveAt(5, 5), restored.captives[1], "Level:captiveAt finds the restored captive by position")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.autopilotNetsABatteredAdjacentMonsterInsteadOfFinishingItInMeleeWhenCarryingANet()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 6, 5, 1)
|
||||||
|
rat.hp = 1
|
||||||
|
game.level.entities = { rat }
|
||||||
|
game.player.inventory[#game.player.inventory + 1] = Items.net()
|
||||||
|
game.rng = Rng.new(2)
|
||||||
|
game:choosePlayerAction()
|
||||||
|
eq(#game.level.captives, 1, "the autopilot nets the battered adjacent monster instead of finishing it off")
|
||||||
|
eq(#game.level.entities, 0, "the netted monster is removed from the level's entities")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.autopilotSellsAHeldCaptiveOnSight()
|
||||||
|
local game = stagedGame(4, arena(21, 11), 5, 5)
|
||||||
|
game.level.captives = { { x = 5, y = 5, species = "rat", faction = Factions.VERMIN, name = "rat", value = 5 } }
|
||||||
|
local goldBefore = game.player.gold
|
||||||
|
game:choosePlayerAction()
|
||||||
|
eq(#game.level.captives, 0, "the autopilot cashes in a held captive on sight")
|
||||||
|
eq(game.player.gold, goldBefore + 5, "the autopilot sells rather than ransoms or interrogates on its own")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.builderOccasionallyPlacesANetFromDepthFive()
|
||||||
|
local level = Builder.build(5, Rng.new(10), {})
|
||||||
|
local found
|
||||||
|
for _, ground in ipairs(level.floorItems) do
|
||||||
|
if ground.item.kind == Items.NET then found = ground.item end
|
||||||
|
end
|
||||||
|
ok(found ~= nil, "this seed's depth-5 floor places a net")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.netsStayOffFloorsAboveDepthFive()
|
||||||
|
for seed = 1, 8 do
|
||||||
|
for depth = 1, 4 do
|
||||||
|
local level = Builder.build(depth, Rng.new(seed), {})
|
||||||
|
for _, ground in ipairs(level.floorItems) do
|
||||||
|
ok(ground.item.kind ~= Items.NET, "no net appears above depth 5")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.hordeBuildArenaIsFullyEnclosedWithAClearCentreReachableFromEveryCorner()
|
||||||
|
local map, cx, cy = Horde.buildArena(Rng.new(1), Horde.WIDTH, Horde.HEIGHT)
|
||||||
|
for x = 1, Horde.WIDTH do
|
||||||
|
eq(map:get(x, 1), Tiles.WALL, "the top border is solid wall")
|
||||||
|
eq(map:get(x, Horde.HEIGHT), Tiles.WALL, "the bottom border is solid wall")
|
||||||
|
end
|
||||||
|
for y = 1, Horde.HEIGHT do
|
||||||
|
eq(map:get(1, y), Tiles.WALL, "the left border is solid wall")
|
||||||
|
eq(map:get(Horde.WIDTH, y), Tiles.WALL, "the right border is solid wall")
|
||||||
|
end
|
||||||
|
ok(map:isWalkable(cx, cy), "the centre cell the player starts on is always clear")
|
||||||
|
for _, anchor in ipairs(Horde.spawnAnchors(Horde.WIDTH, Horde.HEIGHT)) do
|
||||||
|
ok(Astar.find(map, cx, cy, anchor.x, anchor.y) ~= nil,
|
||||||
|
"every corner anchor is reachable from the centre")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.hordeBuildArenaIsDeterministicForAFixedSeedAndDiffersAcrossSeeds()
|
||||||
|
local mapA = Horde.buildArena(Rng.new(5), Horde.WIDTH, Horde.HEIGHT)
|
||||||
|
local mapB = Horde.buildArena(Rng.new(5), Horde.WIDTH, Horde.HEIGHT)
|
||||||
|
eq(table.concat(mapA.tiles), table.concat(mapB.tiles), "the same seed always carves the same pillars")
|
||||||
|
local mapC = Horde.buildArena(Rng.new(6), Horde.WIDTH, Horde.HEIGHT)
|
||||||
|
ok(table.concat(mapA.tiles) ~= table.concat(mapC.tiles), "a different seed carves a different arena")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.hordeSpawnPointsAreUniqueWalkableCellsAndAlwaysCoverAMaxWave()
|
||||||
|
local map = Horde.buildArena(Rng.new(3), Horde.WIDTH, Horde.HEIGHT)
|
||||||
|
local points = Horde.spawnPoints(map)
|
||||||
|
ok(#points >= Horde.MAX_COUNT, "the spawn queue always has room for a maximum-size wave")
|
||||||
|
local seen = {}
|
||||||
|
for _, point in ipairs(points) do
|
||||||
|
local key = point.x .. "," .. point.y
|
||||||
|
ok(not seen[key], "no spawn cell is ever offered twice")
|
||||||
|
seen[key] = true
|
||||||
|
ok(map:isWalkable(point.x, point.y), "every offered spawn cell is walkable")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.hordeCountForClimbsWithWaveThenCapsAtMaxCount()
|
||||||
|
eq(Horde.countFor(1), Horde.BASE_COUNT, "wave one spawns the base count")
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user