test: cover tests.craftingFieldsSurviveSerialization
This commit is contained in:
1 parent
bf8645b0ad
commit
1d0de98b92
1 file changed
+173
+173
@@ -2897,6 +2897,179 @@ function tests.gameCraftingWrappersDriveTheFullPipeline()
|
||||
end
|
||||
|
||||
function tests.monsterKillsGrantEssenceScaledToTheirXpReward()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local rat = Monsters.create(Monsters.byKey.rat, 1, 4, 6, 1)
|
||||
rat.hp = 1
|
||||
game.level.entities = { rat }
|
||||
local essenceBefore = game.player.essence
|
||||
game:playerAttack(rat)
|
||||
eq(game.player.essence, essenceBefore + Crafting.essenceFor(Monsters.xpFor(rat)),
|
||||
"a kill grants essence scaled to the monster's xp reward")
|
||||
end
|
||||
|
||||
function tests.craftingFieldsSurviveSerialization()
|
||||
local game = Game.new(5)
|
||||
local weapon = Items.weapon("dagger", 2)
|
||||
Items.equipWeapon(weapon, game.player)
|
||||
Crafting.socket(game.player, weapon, Crafting.gem(Crafting.VENOM, 2))
|
||||
game.player.essence = 37
|
||||
game.player.inventory[#game.player.inventory + 1] = Crafting.gem(Crafting.SHOCK, 1)
|
||||
|
||||
local path = os.tmpname()
|
||||
game:save(path)
|
||||
local restored = Game.load(path)
|
||||
os.remove(path)
|
||||
|
||||
eq(restored.player.essence, 37, "essence survives a save/load round trip")
|
||||
eq(restored.player.weapon.socket.element, Crafting.VENOM, "a socketed gem's element survives a save/load round trip")
|
||||
eq(restored.player.weapon.socket.tier, 2, "a socketed gem's tier survives a save/load round trip")
|
||||
local restoredGem
|
||||
for _, item in ipairs(restored.player.inventory) do
|
||||
if item.kind == Items.GEM then restoredGem = item end
|
||||
end
|
||||
ok(restoredGem ~= nil, "a loose gem in the inventory survives a save/load round trip")
|
||||
eq(restoredGem.element, Crafting.SHOCK, "the loose gem's element survives a save/load round trip")
|
||||
end
|
||||
|
||||
function tests.alchemyBrewResolvesAKnownPairToItsFixedPotion()
|
||||
local potion = Alchemy.brew(Alchemy.SUNPETAL, Alchemy.SUNPETAL)
|
||||
eq(potion.effect, "heal", "a matched pair of the same herb brews that herb's aspect")
|
||||
eq(potion.power, 18, "a doubled herb brews a stronger potion than a mixed pair")
|
||||
end
|
||||
|
||||
function tests.alchemyBrewIsOrderIndependent()
|
||||
local forward = Alchemy.brew(Alchemy.BLOODROOT, Alchemy.NIGHTCAP)
|
||||
local backward = Alchemy.brew(Alchemy.NIGHTCAP, Alchemy.BLOODROOT)
|
||||
eq(forward.effect, backward.effect, "brewing a pair does not depend on which herb is named first")
|
||||
eq(forward.power, backward.power, "a brewed potion's power does not depend on herb order either")
|
||||
end
|
||||
|
||||
function tests.alchemyBrewCurdlesOnAnOpposedPairing()
|
||||
local potion, reason = Alchemy.brew(Alchemy.SUNPETAL, Alchemy.NIGHTCAP)
|
||||
eq(potion, nil, "light and shade herbs curdle rather than brewing a potion")
|
||||
eq(reason, "curdle", "a curdled brew names its failure")
|
||||
end
|
||||
|
||||
function tests.alchemyLookupRejectsAnUnknownHerb()
|
||||
eq(Alchemy.lookup("mud", Alchemy.SUNPETAL), nil, "a nonexistent herb key has no recipe")
|
||||
end
|
||||
|
||||
function tests.gameBrewAtCombinesTwoHerbsIntoAPotionAtACauldron()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.level.cauldrons = { { x = 5, y = 5 } }
|
||||
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Alchemy.herb(Alchemy.BLOODROOT) }
|
||||
ok(game:brewAt(1, 2), "brewing two herbs at a cauldron underfoot succeeds")
|
||||
eq(#game.player.inventory, 1, "both source herbs are spent and one potion is added")
|
||||
local brewed = game.player.inventory[1]
|
||||
eq(brewed.kind, Items.POTION, "brewing yields an ordinary catalog potion")
|
||||
eq(brewed.effect, "heal", "the brewed potion matches the herb pair's fixed recipe")
|
||||
eq(brewed.power, 10, "the brewed potion's power matches the recipe, not the catalog default")
|
||||
ok(Identify.isKnown(game.identify, brewed), "brewing a potion yourself identifies its type for free")
|
||||
end
|
||||
|
||||
function tests.gameBrewAtFailsWithoutACauldronUnderfoot()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Alchemy.herb(Alchemy.BLOODROOT) }
|
||||
ok(not game:brewAt(1, 2), "brewing away from any cauldron fails")
|
||||
eq(#game.player.inventory, 2, "a failed brew for lack of a cauldron spends nothing")
|
||||
end
|
||||
|
||||
function tests.gameBrewAtRequiresTwoHerbItems()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.level.cauldrons = { { x = 5, y = 5 } }
|
||||
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL) }
|
||||
ok(not game:brewAt(1, 1), "brewing a herb against itself by index is rejected")
|
||||
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Items.potion(10) }
|
||||
ok(not game:brewAt(1, 2), "a non-herb item cannot stand in for the second half of a brew")
|
||||
eq(#game.player.inventory, 2, "a rejected brew attempt spends nothing")
|
||||
end
|
||||
|
||||
function tests.gameBrewAtCurdlesIntoGasInsteadOfAPotion()
|
||||
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||
game.level.cauldrons = { { x = 5, y = 5 } }
|
||||
game.player.inventory = { Alchemy.herb(Alchemy.SUNPETAL), Alchemy.herb(Alchemy.NIGHTCAP) }
|
||||
ok(not game:brewAt(1, 2), "a curdled brew reports failure")
|
||||
eq(#game.player.inventory, 0, "a curdled brew still spends both herbs")
|
||||
ok(Hazards.at(game.level, 5, 5, Hazards.GAS) ~= nil, "a curdled brew vents a gas hazard at the brewer's feet")
|
||||
ok(contains(game.log:recent(1)[1] or "", "curdle"), "the curdle is logged")
|
||||
end
|
||||
|
||||
function tests.buildersScatterHerbsFromTheFirstFloor()
|
||||
local level = Builder.build(1, Rng.new(1), {})
|
||||
local herbs = 0
|
||||
for _, ground in ipairs(level.floorItems) do
|
||||
if ground.item.kind == Items.HERB then herbs = herbs + 1 end
|
||||
end
|
||||
ok(herbs >= 2, "the entrance floor already scatters foraging herbs")
|
||||
end
|
||||
|
||||
function tests.cauldronsStayOffTheEntranceFloor()
|
||||
for seed = 1, 5 do
|
||||
local level = Builder.build(1, Rng.new(seed), {})
|
||||
eq(#level.cauldrons, 0, "no cauldron appears on the entrance floor")
|
||||
end
|
||||
end
|
||||
|
||||
function tests.buildersOccasionallyPlaceACauldronFromDepthTwo()
|
||||
local level = Builder.build(2, Rng.new(14), {})
|
||||
eq(#level.cauldrons, 1, "this seed's depth-2 floor places a cauldron")
|
||||
end
|
||||
|
||||
function tests.cauldronFieldsSurviveSerialization()
|
||||
local level = arena(21, 11)
|
||||
level.cauldrons = { { x = 4, y = 4 } }
|
||||
local restored = Level.fromData(level:toData())
|
||||
eq(#restored.cauldrons, 1, "the cauldron list survives a round trip")
|
||||
eq(restored.cauldrons[1].x, 4, "a cauldron's position survives a round trip")
|
||||
end
|
||||
|
||||
function tests.cauldronRendersItsGlyphWhenVisible()
|
||||
local rendered = stagedGame(1, arena(21, 11), 3, 6)
|
||||
rendered.level.cauldrons = { { x = 5, y = 6 } }
|
||||
rendered:computeVisible()
|
||||
ok(contains(rendered:render(), "U"), "a cauldron on a visible cell renders as its glyph")
|
||||
end
|
||||
|
||||
local function nodePlayer()
|
||||
return { essence = 0, inventory = {} }
|
||||
end
|
||||
|
||||
local function nodeGame(seed)
|
||||
local game = { player = nodePlayer(), rng = Rng.new(seed), level = { event = nil }, ascension = {} }
|
||||
function game:essenceMultiplier()
|
||||
return Events.essenceMultiplier(self.level.event) * Ascension.essenceMultiplier(self.ascension)
|
||||
end
|
||||
return game
|
||||
end
|
||||
|
||||
function tests.nodesHarvestingAnOreVeinPaysEssenceAndSpendsACharge()
|
||||
local node = Nodes.new(Nodes.ORE)
|
||||
local game = nodeGame(3)
|
||||
local success, line = Nodes.harvest(game, node)
|
||||
ok(success, "harvesting a fresh ore vein succeeds")
|
||||
eq(node.charges, Nodes.MAX_CHARGES - 1, "a harvest spends exactly one charge")
|
||||
ok(game.player.essence >= Nodes.ORE_YIELD_MIN and game.player.essence <= Nodes.ORE_YIELD_MAX,
|
||||
"the essence paid out falls within the vein's yield range")
|
||||
ok(contains(line, "essence"), "the harvest is logged")
|
||||
end
|
||||
|
||||
function tests.nodesHarvestingAnOreVeinDoublesItsYieldDuringRichVeins()
|
||||
local node = Nodes.new(Nodes.ORE)
|
||||
local game = nodeGame(3)
|
||||
game.level.event = { key = Events.RICHVEINS, turnsLeft = 5 }
|
||||
Nodes.harvest(game, node)
|
||||
ok(game.player.essence >= Nodes.ORE_YIELD_MIN * 2 and game.player.essence <= Nodes.ORE_YIELD_MAX * 2,
|
||||
"rich veins doubles the vein's ordinary yield range")
|
||||
end
|
||||
|
||||
function tests.nodesHarvestingAGemSeamYieldsARawTierOneGemOfItsElement()
|
||||
local node = Nodes.new(Nodes.GEM, Crafting.FIRE)
|
||||
local game = nodeGame(3)
|
||||
local success = Nodes.harvest(game, node)
|
||||
ok(success, "harvesting a fresh gem seam succeeds")
|
||||
eq(#game.player.inventory, 1, "a gem lands in the inventory")
|
||||
local gem = game.player.inventory[1]
|
||||
eq(gem.kind, Items.GEM, "the yield is a gem item")
|
||||
end
|
||||
|
||||
local order = {
|
||||
|
||||
Reference in new issue
Block a user