test: cover tests.nodesGoingFallowRefusesFurtherHarvestsUntilItReopens
This commit is contained in:
1 parent
1d0de98b92
commit
183e67da75
1 file changed
+173
+173
@@ -3070,6 +3070,179 @@ function tests.nodesHarvestingAGemSeamYieldsARawTierOneGemOfItsElement()
|
|||||||
eq(#game.player.inventory, 1, "a gem lands in the inventory")
|
eq(#game.player.inventory, 1, "a gem lands in the inventory")
|
||||||
local gem = game.player.inventory[1]
|
local gem = game.player.inventory[1]
|
||||||
eq(gem.kind, Items.GEM, "the yield is a gem item")
|
eq(gem.kind, Items.GEM, "the yield is a gem item")
|
||||||
|
eq(gem.element, Crafting.FIRE, "the gem matches the seam's own element")
|
||||||
|
eq(gem.tier, 1, "a freshly pried gem is raw, tier one")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.nodesGoingFallowRefusesFurtherHarvestsUntilItReopens()
|
||||||
|
local node = Nodes.new(Nodes.ORE)
|
||||||
|
node.charges = 1
|
||||||
|
local game = nodeGame(9)
|
||||||
|
ok(Nodes.harvest(game, node), "the last charge still pays out")
|
||||||
|
eq(node.charges, 0, "spending the last charge empties the vein")
|
||||||
|
eq(node.cooldown, Nodes.REGEN_TURNS, "emptying a vein starts its regen cooldown")
|
||||||
|
local success, line = Nodes.harvest(game, node)
|
||||||
|
eq(success, false, "a fallow vein refuses to be harvested again")
|
||||||
|
ok(contains(line, "played out"), "the refusal is logged")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.nodesStepCountsDownAndReopensAFallowNode()
|
||||||
|
local level = { nodes = { Nodes.new(Nodes.ORE) } }
|
||||||
|
local node = level.nodes[1]
|
||||||
|
node.charges = 0
|
||||||
|
node.cooldown = 2
|
||||||
|
Nodes.step(level)
|
||||||
|
eq(node.cooldown, 1, "each step counts the cooldown down by one")
|
||||||
|
eq(node.charges, 0, "the vein stays fallow until its cooldown reaches zero")
|
||||||
|
Nodes.step(level)
|
||||||
|
eq(node.cooldown, 0, "the cooldown reaches zero on schedule")
|
||||||
|
eq(node.charges, Nodes.MAX_CHARGES, "reaching zero cooldown fully reopens the vein")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.nodesFieldsSurviveSerialization()
|
||||||
|
local level = arena(21, 11)
|
||||||
|
local node = Nodes.new(Nodes.GEM, Crafting.FROST)
|
||||||
|
node.x, node.y = 4, 4
|
||||||
|
node.charges = 1
|
||||||
|
node.cooldown = 5
|
||||||
|
level.nodes = { node }
|
||||||
|
local restored = Level.fromData(level:toData())
|
||||||
|
eq(#restored.nodes, 1, "the node list survives a round trip")
|
||||||
|
eq(restored.nodes[1].kind, Nodes.GEM, "a node's kind survives a round trip")
|
||||||
|
eq(restored.nodes[1].element, Crafting.FROST, "a node's element survives a round trip")
|
||||||
|
eq(restored.nodes[1].charges, 1, "a node's charges survive a round trip")
|
||||||
|
eq(restored.nodes[1].cooldown, 5, "a node's cooldown survives a round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.nodeRendersItsGlyphWhenVisible()
|
||||||
|
local rendered = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local ore = Nodes.new(Nodes.ORE)
|
||||||
|
ore.x, ore.y = 5, 6
|
||||||
|
rendered.level.nodes = { ore }
|
||||||
|
rendered:computeVisible()
|
||||||
|
ok(contains(rendered:render(), "O"), "an ore vein on a visible cell renders as its glyph")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameHarvestNodeAtAnOreVeinAddsEssenceAndSpendsACharge()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local ore = Nodes.new(Nodes.ORE)
|
||||||
|
ore.x, ore.y = 5, 5
|
||||||
|
game.level.nodes = { ore }
|
||||||
|
local before = game.player.essence
|
||||||
|
ok(game:harvestNode(), "harvesting the ore vein underfoot succeeds")
|
||||||
|
ok(game.player.essence > before, "harvesting an ore vein raises the player's essence")
|
||||||
|
eq(ore.charges, Nodes.MAX_CHARGES - 1, "harvesting spends one of the vein's charges")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameHarvestNodeFailsWithoutANodeUnderfoot()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
ok(not game:harvestNode(), "harvesting empty ground fails")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameHarvestNodeOnAFallowVeinFails()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local ore = Nodes.new(Nodes.ORE)
|
||||||
|
ore.x, ore.y, ore.charges = 5, 5, 0
|
||||||
|
game.level.nodes = { ore }
|
||||||
|
ok(not game:harvestNode(), "a fallow vein cannot be harvested")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.autopilotHarvestsAnOreVeinWhenIdleAndStandingOnIt()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local ore = Nodes.new(Nodes.ORE)
|
||||||
|
ore.x, ore.y = 5, 5
|
||||||
|
game.level.nodes = { ore }
|
||||||
|
local before = game.player.essence
|
||||||
|
game:choosePlayerAction()
|
||||||
|
eq(ore.charges, Nodes.MAX_CHARGES - 1, "the autopilot harvests an unspent vein it stands on")
|
||||||
|
ok(game.player.essence > before, "the autopilot's harvest actually pays out essence")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.autopilotSkipsAFallowNode()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
local ore = Nodes.new(Nodes.ORE)
|
||||||
|
ore.x, ore.y, ore.charges = 5, 5, 0
|
||||||
|
game.level.nodes = { ore }
|
||||||
|
game:choosePlayerAction()
|
||||||
|
eq(ore.charges, 0, "the autopilot never touches a fallow node")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.buildersNeverPlaceANodeOnTheEntranceFloor()
|
||||||
|
for seed = 1, 5 do
|
||||||
|
local level = Builder.build(1, Rng.new(seed), {})
|
||||||
|
eq(#level.nodes, 0, "no resource node appears on the entrance floor")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.buildersAlwaysPlaceAtLeastOneNodeFromDepthTwoOn()
|
||||||
|
for seed = 1, 5 do
|
||||||
|
for depth = 2, 5 do
|
||||||
|
local level = Builder.build(depth, Rng.new(seed), {})
|
||||||
|
ok(#level.nodes >= 1, "every depth-2-and-deeper floor places at least one resource node")
|
||||||
|
ok(#level.nodes <= 2, "no floor places more than two resource nodes")
|
||||||
|
for _, node in ipairs(level.nodes) do
|
||||||
|
ok(node.kind == Nodes.ORE or node.kind == Nodes.GEM, "every placed node is a known kind")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function corpsePlayer()
|
||||||
|
return { inventory = {}, statuses = {} }
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.corpsesSpawnsForAWildMonsterButNotForUndeadMimicOrBoss()
|
||||||
|
local level = { corpses = {} }
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 5, 5, 1)
|
||||||
|
Corpses.spawn(level, rat)
|
||||||
|
eq(#level.corpses, 1, "a wild monster leaves a corpse behind")
|
||||||
|
|
||||||
|
local zombie = Monsters.create(Monsters.byKey.zombie, 2, 6, 6, 4)
|
||||||
|
Corpses.spawn(level, zombie)
|
||||||
|
eq(#level.corpses, 1, "an undead monster crumbles to dust, leaving no corpse")
|
||||||
|
|
||||||
|
local mimic = Mimics.reveal(3, 7, 7, 4)
|
||||||
|
Corpses.spawn(level, mimic)
|
||||||
|
eq(#level.corpses, 1, "a mimic was never alive, so it leaves no corpse")
|
||||||
|
|
||||||
|
local warlord = Bosses.create(Bosses.byKey.warlord, 4, 8, 8)
|
||||||
|
Corpses.spawn(level, warlord)
|
||||||
|
eq(#level.corpses, 1, "a boss's own scripted loot drop replaces a corpse")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.corpsesNutritionScalesWithTheFelledSpeciesMaxHpClampedToAFixedBand()
|
||||||
|
local bat = Monsters.create(Monsters.byKey.bat, 1, 5, 5, 1)
|
||||||
|
local batCorpse = Corpses.new(bat)
|
||||||
|
eq(batCorpse.nutrition, Corpses.NUTRITION_MIN, "a frail species clamps to the nutrition floor")
|
||||||
|
|
||||||
|
local troll = Monsters.create(Monsters.byKey.troll, 2, 5, 5, 5)
|
||||||
|
local trollCorpse = Corpses.new(troll)
|
||||||
|
eq(trollCorpse.nutrition, troll.maxHp * Corpses.NUTRITION_PER_HP, "a tougher species scales nutrition with maxHp")
|
||||||
|
|
||||||
|
local dragon = Monsters.create(Monsters.byKey.dragon, 3, 5, 5, 6)
|
||||||
|
local dragonCorpse = Corpses.new(dragon)
|
||||||
|
eq(dragonCorpse.nutrition, Corpses.NUTRITION_MAX, "an especially tough species clamps to the nutrition ceiling")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.corpsesStepCountsDownAndRotsAwayEntirely()
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 5, 5, 1)
|
||||||
|
local level = { corpses = {} }
|
||||||
|
Corpses.spawn(level, rat)
|
||||||
|
local corpse = level.corpses[1]
|
||||||
|
for _ = 1, Corpses.DECAY_TURNS - 1 do Corpses.step(level) end
|
||||||
|
eq(#level.corpses, 1, "a corpse survives right up to its final round")
|
||||||
|
eq(corpse.decay, 1, "decay counts down by exactly one each step")
|
||||||
|
Corpses.step(level)
|
||||||
|
eq(#level.corpses, 0, "a corpse vanishes outright once its decay reaches zero")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.corpsesGoesRottenPastItsThresholdButStaysButcherableUntilThen()
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 1, 5, 5, 1)
|
||||||
|
local corpse = Corpses.new(rat)
|
||||||
|
ok(not Corpses.isRotten(corpse), "a freshly spawned corpse is not yet rotten")
|
||||||
|
corpse.decay = Corpses.ROT_TURNS
|
||||||
|
ok(Corpses.isRotten(corpse), "a corpse right at its rot threshold counts as rotten")
|
||||||
|
corpse.decay = Corpses.ROT_TURNS + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user