test: cover tests.amuletSpawnsOnFinalFloorOnly
This commit is contained in:
1 parent
abc27cd5e1
commit
e7b64c1e92
1 file changed
+173
+173
@@ -2034,6 +2034,179 @@ function tests.autoplayDescends()
|
||||
eq(again.turn, run.turn, "the autopilot takes the same number of turns")
|
||||
end
|
||||
|
||||
function tests.amuletSpawnsOnFinalFloorOnly()
|
||||
local finalLevel = Builder.build(Builder.MAX_DEPTH, Rng.new(999), {})
|
||||
local finalCount = 0
|
||||
for _, ground in ipairs(finalLevel.floorItems) do
|
||||
if ground.item.kind == Items.AMULET then finalCount = finalCount + 1 end
|
||||
end
|
||||
eq(finalCount, 1, "exactly one amulet is placed on the final floor")
|
||||
|
||||
local shallowLevel = Builder.build(Builder.MAX_DEPTH - 1, Rng.new(999), {})
|
||||
local shallowCount = 0
|
||||
for _, ground in ipairs(shallowLevel.floorItems) do
|
||||
if ground.item.kind == Items.AMULET then shallowCount = shallowCount + 1 end
|
||||
end
|
||||
eq(shallowCount, 0, "no amulet appears above the final floor")
|
||||
end
|
||||
|
||||
function tests.descendIsBlockedAtTheFinalFloor()
|
||||
local game = Game.new(555)
|
||||
game.depth = game.maxDepth
|
||||
game.level = game.dungeon:get(game.maxDepth)
|
||||
game.player.x, game.player.y = game.level.downX, game.level.downY
|
||||
local result = game:descend()
|
||||
eq(result, false, "descend fails once at the final floor")
|
||||
eq(game.depth, game.maxDepth, "depth is unchanged after a blocked descend")
|
||||
ok(contains(game.log:last(), "rock"), "a message explains why the descent is blocked")
|
||||
end
|
||||
|
||||
function tests.ascendWithoutAmuletDoesNotWin()
|
||||
local game = Game.new(7)
|
||||
game.player.x, game.player.y = game.level.upX, game.level.upY
|
||||
local result = game:ascend()
|
||||
eq(result, true, "climbing out at depth 1 is still a valid move")
|
||||
eq(game.won, false, "climbing out without the amulet does not win the game")
|
||||
end
|
||||
|
||||
function tests.ascendWithAmuletWinsTheGame()
|
||||
local game = Game.new(7)
|
||||
game.player.inventory[#game.player.inventory + 1] = Items.amulet()
|
||||
game.player.x, game.player.y = game.level.upX, game.level.upY
|
||||
local result = game:ascend()
|
||||
eq(result, true, "climbing out at depth 1 with the amulet succeeds")
|
||||
eq(game.won, true, "carrying the amulet to the surface wins the game")
|
||||
ok(contains(game.log:last(), "win"), "the victory is logged")
|
||||
end
|
||||
|
||||
function tests.wonGameHaltsTheAutopilot()
|
||||
local game = Game.new(7)
|
||||
game.won = true
|
||||
local turnBefore = game.turn
|
||||
game:autoStep()
|
||||
eq(game.turn, turnBefore, "autoStep is a no-op once the game is already won")
|
||||
end
|
||||
|
||||
function tests.autopilotFetchesTheAmuletAndWins()
|
||||
local function playout(seed)
|
||||
local game = Game.new(seed, { maxDepth = 3 })
|
||||
for _ = 1, 900 do
|
||||
if not game.player:isAlive() or game.won then break end
|
||||
game:autoStep()
|
||||
end
|
||||
return game
|
||||
end
|
||||
local run = playout(67)
|
||||
ok(run.player:isAlive(), "the autopilot survives the round trip on this seed")
|
||||
eq(run.won, true, "the autopilot retrieves the amulet and escapes")
|
||||
eq(run.depth, 1, "winning leaves the player back at depth 1")
|
||||
ok(run:hasAmulet(), "the amulet is still in the winning player's inventory")
|
||||
local again = playout(67)
|
||||
eq(again.turn, run.turn, "the winning playthrough takes the same number of turns on the same seed")
|
||||
end
|
||||
|
||||
function tests.shopPriceCatalogScalesWithPower()
|
||||
local base = Shop.priceOf(Items.weapon("dagger", 2))
|
||||
local strong = Shop.priceOf(Items.weapon("battle axe", 5))
|
||||
ok(strong > base, "a more powerful weapon costs more at the shop")
|
||||
eq(Shop.priceOf(Items.potionOf("heal")), 15, "a catalogued potion has its fixed price")
|
||||
eq(Shop.sellValue(Items.potionOf("heal")), 7, "selling nets half the catalog price, rounded down")
|
||||
end
|
||||
|
||||
function tests.shopStockRollsAffordableWares()
|
||||
local wares = Shop.stock(Rng.new(7))
|
||||
ok(#wares >= 3 and #wares <= 5, "a shop rolls three to five wares")
|
||||
for _, item in ipairs(wares) do
|
||||
ok(Shop.priceOf(item) > 0, "every ware has a positive price")
|
||||
end
|
||||
end
|
||||
|
||||
function tests.goldPickupAddsToWalletNotInventory()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||
local before = #game.player.inventory
|
||||
local goldBefore = game.player.gold
|
||||
game.level.floorItems = { { x = 4, y = 3, item = Items.gold(35) } }
|
||||
game:movePlayer(1, 0)
|
||||
eq(game.player.gold, goldBefore + 35, "walking onto gold adds it to the wallet")
|
||||
eq(#game.player.inventory, before, "gold never occupies an inventory slot")
|
||||
eq(#game.level.floorItems, 0, "the gold pile is removed from the floor")
|
||||
end
|
||||
|
||||
function tests.affordableWareIsBoughtAutomaticallyOnPickup()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 10, 10, 4)
|
||||
game.level.entities = { keeper }
|
||||
game.player.gold = 50
|
||||
local before = #game.player.inventory
|
||||
game.level.floorItems = { { x = 4, y = 3, item = Items.potionOf("heal"), price = 15, shopId = keeper.id } }
|
||||
game:movePlayer(1, 0)
|
||||
eq(game.player.gold, 35, "the ware's stamped price is deducted from the wallet")
|
||||
eq(#game.player.inventory, before + 1, "the bought ware joins the inventory")
|
||||
eq(#game.level.floorItems, 0, "the purchased ware leaves the ground")
|
||||
end
|
||||
|
||||
function tests.unaffordableWareStaysOnTheGround()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 10, 10, 4)
|
||||
game.level.entities = { keeper }
|
||||
game.player.gold = 5
|
||||
local before = #game.player.inventory
|
||||
game.level.floorItems = { { x = 4, y = 3, item = Items.potionOf("heal"), price = 15, shopId = keeper.id } }
|
||||
game:movePlayer(1, 0)
|
||||
eq(game.player.gold, 5, "an unaffordable ware is never bought, so no gold changes hands")
|
||||
eq(#game.player.inventory, before, "the ware never reaches the inventory")
|
||||
eq(#game.level.floorItems, 1, "the unbought ware is left in place")
|
||||
end
|
||||
|
||||
function tests.deadKeeperMakesWaresFreeToLoot()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 10, 10, 4)
|
||||
keeper.hp = 0
|
||||
game.level.entities = { keeper }
|
||||
game.player.gold = 0
|
||||
local before = #game.player.inventory
|
||||
game.level.floorItems = { { x = 4, y = 3, item = Items.potionOf("heal"), price = 15, shopId = keeper.id } }
|
||||
game:movePlayer(1, 0)
|
||||
eq(game.player.gold, 0, "looting a dead keeper's stock costs nothing")
|
||||
eq(#game.player.inventory, before + 1, "the ware is picked up normally once its keeper is dead")
|
||||
end
|
||||
|
||||
function tests.stealingFromShopTurnsTheKeeperHostile()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 10, 10, 4)
|
||||
game.level.entities = { keeper }
|
||||
game.player.gold = 0
|
||||
local before = #game.player.inventory
|
||||
game.level.floorItems = { { x = 4, y = 3, item = Items.scroll("identify"), price = 18, shopId = keeper.id } }
|
||||
local stolen = game:stealFromShop(1)
|
||||
eq(stolen, true, "stealing succeeds against a live keeper's ware")
|
||||
eq(game.player.gold, 0, "theft costs no gold")
|
||||
eq(#game.player.inventory, before + 1, "the stolen item joins the inventory")
|
||||
eq(keeper.hostile, true, "the keeper turns hostile after the theft")
|
||||
ok(contains(game.log:last(), "steal"), "the theft is logged")
|
||||
end
|
||||
|
||||
function tests.hostileShopkeeperChasesLikeAnyMonster()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 8, 6, 4)
|
||||
keeper.hostile = true
|
||||
game.level.entities = { keeper }
|
||||
Ai.act(game, keeper)
|
||||
eq(keeper.x, 7, "a hostile shopkeeper closes in on the player like a chaser")
|
||||
end
|
||||
|
||||
function tests.passiveShopkeeperIgnoresTheAdjacentPlayer()
|
||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||
local keeper = Monsters.create(Monsters.byKey.shopkeeper, 1, 4, 6, 4)
|
||||
game.level.entities = { keeper }
|
||||
local hpBefore = game.player.hp
|
||||
Ai.act(game, keeper)
|
||||
eq(keeper.x, 4, "an un-robbed shopkeeper does not move")
|
||||
eq(game.player.hp, hpBefore, "an un-robbed shopkeeper does not attack even when adjacent")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local order = {
|
||||
"rngDeterminism", "mapDeterminism", "tilesRegistry", "fovKnownScene", "losSightLine",
|
||||
"astarPathing", "combatResolution", "itemsAndEquipment", "affixes", "statusEffects",
|
||||
|
||||
Reference in new issue
Block a user