test: cover tests.factionAndProvokedFieldsSurviveEntitySerialization
This commit is contained in:
1 parent
90bf3238ac
commit
6995189118
1 file changed
+173
+173
@@ -5667,6 +5667,179 @@ function tests.factionsAppeaseFailsOnceAFactionIsAlreadyMaxedOut()
|
|||||||
eq(player.gold, 1000, "nothing is spent when there is nothing to buy")
|
eq(player.gold, 1000, "nothing is spent when there is nothing to buy")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tests.factionAndProvokedFieldsSurviveEntitySerialization()
|
||||||
|
local kobold = Monsters.create(Monsters.byKey.kobold, 1, 1, 1, 1)
|
||||||
|
kobold.provoked = true
|
||||||
|
local restored = Entity.fromData(kobold:toData())
|
||||||
|
eq(restored.faction, Factions.GOBLINOID, "a monster's faction tag survives a round trip")
|
||||||
|
eq(restored.provoked, true, "a monster's provoked flag survives a round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameTakeMonsterTurnLeavesAWaryGoblinoidAloneUntilProvoked()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local kobold = Monsters.create(Monsters.byKey.kobold, 1, 4, 6, 1)
|
||||||
|
game.level.entities = { kobold }
|
||||||
|
local hpBefore = game.player.hp
|
||||||
|
game:takeMonsterTurn(kobold)
|
||||||
|
eq(kobold.x, 4, "an unprovoked kobold does not close in")
|
||||||
|
eq(game.player.hp, hpBefore, "an unprovoked kobold does not attack even when adjacent")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gamePlayerAttackProvokesAWaryGoblinoidSoItFightsBackNextTurn()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local kobold = Monsters.create(Monsters.byKey.kobold, 1, 4, 6, 1)
|
||||||
|
kobold.hp = 100
|
||||||
|
game.level.entities = { kobold }
|
||||||
|
game:playerAttack(kobold)
|
||||||
|
eq(kobold.provoked, true, "aiming a melee attack at a wary goblinoid provokes it")
|
||||||
|
local hpBefore = game.player.hp
|
||||||
|
game:takeMonsterTurn(kobold)
|
||||||
|
ok(game.player.hp < hpBefore, "a provoked, adjacent kobold now fights back")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameAwardKillSoursFactionReputationWithTheFallensFaction()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 4, 6, 1)
|
||||||
|
orc.hp = 1
|
||||||
|
game.level.entities = { orc }
|
||||||
|
game:playerAttack(orc)
|
||||||
|
eq(orc:isAlive(), false, "the orc dies to the hit")
|
||||||
|
eq(Factions.reputationFor(game.player, Factions.ORCISH), -5, "the kill sours standing with the orc's faction")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.shopBuyIsMarkedUpWhenMerchantsAreHostile()
|
||||||
|
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 = 100
|
||||||
|
Factions.adjust(game.player, Factions.MERCHANT, -40)
|
||||||
|
game.level.floorItems = { { x = 4, y = 3, item = Items.potionOf("heal"), price = 15, shopId = keeper.id } }
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
eq(game.player.gold, 78, "a hostile guild marks the stamped price up by half, floored")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.shopBuyIsDiscountedWhenMerchantsAreHonored()
|
||||||
|
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 = 100
|
||||||
|
Factions.adjust(game.player, Factions.MERCHANT, 60)
|
||||||
|
game.level.floorItems = { { x = 4, y = 3, item = Items.potionOf("heal"), price = 15, shopId = keeper.id } }
|
||||||
|
game:movePlayer(1, 0)
|
||||||
|
eq(game.player.gold, 91, "an honored guild discounts the stamped price, floored")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.shopSellValueRisesWithMerchantStanding()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
game.player.inventory = { Items.potionOf("heal") }
|
||||||
|
local goldBefore = game.player.gold
|
||||||
|
Factions.adjust(game.player, Factions.MERCHANT, 60)
|
||||||
|
local value = game:sellItem(1)
|
||||||
|
eq(value, 10, "an honored guild pays more than the neutral half-price for the same ware")
|
||||||
|
eq(game.player.gold, goldBefore + 10, "the sale proceeds land in the wallet")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.stealingFromShopAlsoSoursMerchantReputation()
|
||||||
|
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.level.floorItems = { { x = 4, y = 3, item = Items.scroll("identify"), price = 18, shopId = keeper.id } }
|
||||||
|
game:stealFromShop(1)
|
||||||
|
eq(Factions.reputationFor(game.player, Factions.MERCHANT), -20, "a theft sours the merchant guild's opinion of the player")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.resolveQuestNudgesMerchantReputationUpward()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.player.quest = { kind = Quests.CULL, species = "rat", need = 1, have = 1, rewardGold = 30, rewardXp = 15 }
|
||||||
|
game:resolveQuest()
|
||||||
|
eq(Factions.reputationFor(game.player, Factions.MERCHANT), 3, "turning in a bounty pads the merchant guild's opinion of the player")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameAppeaseFactionSpendsGoldAndLogsTheOutcome()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
game.player.gold = 100
|
||||||
|
local success = game:appeaseFaction(Factions.GOBLINOID)
|
||||||
|
eq(success, true, "a well-funded tribute succeeds")
|
||||||
|
eq(game.player.gold, 80, "the tribute's cost is deducted from the wallet")
|
||||||
|
eq(Factions.reputationFor(game.player, Factions.GOBLINOID), 15, "the tribute raises standing")
|
||||||
|
ok(contains(game.log:last(), "goblinoid"), "the successful tribute is logged")
|
||||||
|
|
||||||
|
game.player.gold = 0
|
||||||
|
local failure = game:appeaseFaction(Factions.BANDIT)
|
||||||
|
eq(failure, false, "an empty purse cannot pay any tribute")
|
||||||
|
ok(contains(game.log:last(), "gold"), "the failed tribute explains the shortfall")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.playerReputationSurvivesGameSaveLoadRoundTrip()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
Factions.adjust(game.player, Factions.GOBLINOID, -40)
|
||||||
|
Factions.adjust(game.player, Factions.MERCHANT, 10)
|
||||||
|
local restored = Game.fromData(game:toData())
|
||||||
|
eq(Factions.reputationFor(restored.player, Factions.GOBLINOID), -40, "goblinoid standing survives a save/load round trip")
|
||||||
|
eq(Factions.reputationFor(restored.player, Factions.MERCHANT), 10, "merchant standing survives a save/load round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Carry weight (encumbrance.lua): a hoard heavy enough to cross a capacity
|
||||||
|
-- threshold slows the carrier down, and a wide overage on top of that also
|
||||||
|
-- costs defense. Weight is derived purely from inventory/equipped items and
|
||||||
|
-- level, so nothing here needs its own save-format handling.
|
||||||
|
|
||||||
|
function tests.encumbranceItemWeightScalesWithGearPower()
|
||||||
|
eq(Encumbrance.itemWeight(Items.weapon("dagger", 2)), 6, "a weak weapon carries close to its flat base weight")
|
||||||
|
eq(Encumbrance.itemWeight(Items.weapon("greatsword", 9)), 9, "a powerful weapon weighs more than a weak one of the same kind")
|
||||||
|
eq(Encumbrance.itemWeight(Items.armor("padded vest", 0)), 9, "armor has its own, heavier, flat base")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.encumbranceAmmoWeightScalesWithStackCount()
|
||||||
|
eq(Encumbrance.itemWeight(Items.ammo("arrow", 1)), 1, "a single arrow weighs its unit weight")
|
||||||
|
eq(Encumbrance.itemWeight(Items.ammo("arrow", 5)), 5, "a stack of arrows weighs the unit weight times the count")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.encumbranceCapacityGrowsWithLevel()
|
||||||
|
eq(Encumbrance.capacityFor({ level = 1 }), 16, "a level 1 carrier's capacity is the flat base plus one level's worth")
|
||||||
|
eq(Encumbrance.capacityFor({ level = 5 }), 32, "capacity scales linearly with level")
|
||||||
|
eq(Encumbrance.capacityFor({}), 16, "a missing level defaults to level 1's capacity")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.encumbranceEquippedGearCountsTowardCarriedWeight()
|
||||||
|
local carrier = {
|
||||||
|
inventory = {},
|
||||||
|
weapon = Items.weapon("sword", 3), armor = Items.armor("mail", 6),
|
||||||
|
ring = Items.ring("band", 1, 1), bow = Items.bow("bow", 2, 3),
|
||||||
|
}
|
||||||
|
eq(Encumbrance.carriedWeight(carrier), 26, "worn and wielded gear counts exactly like the same items in the pack")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.encumbranceLightLoadHasNoPenalty()
|
||||||
|
local game = Game.new(1)
|
||||||
|
eq(game.player:encumbranceTier(), Encumbrance.LIGHT, "a fresh player's starting kit is well under capacity")
|
||||||
|
eq(game.player:effectiveSpeed(), 100, "a light load never slows the carrier down")
|
||||||
|
eq(game.player:effectiveDefense(), 1, "a light load never costs defense")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Each padding armor has zero power (so bestUpgrade never mistakes it for an
|
||||||
|
-- upgrade) and so weighs exactly the base 9.
|
||||||
|
local function padWith(entity, count)
|
||||||
|
for _ = 1, count do
|
||||||
|
entity.inventory[#entity.inventory + 1] = Items.armor("lockbox", 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.encumbranceBurdenedSlowsMovementButNotDefense()
|
||||||
|
local game = Game.new(1)
|
||||||
|
game.player.inventory = {}
|
||||||
|
padWith(game.player, 2)
|
||||||
|
ok(Encumbrance.carriedWeight(game.player) > Encumbrance.capacityFor(game.player),
|
||||||
|
"two heavy armors alone clear the fresh player's capacity")
|
||||||
|
eq(game.player:encumbranceTier(), Encumbrance.BURDENED, "a moderate overage is merely burdened")
|
||||||
|
eq(game.player:effectiveSpeed(), 80, "a burdened carrier loses a flat chunk of speed")
|
||||||
|
eq(game.player:effectiveDefense(), 1, "a burdened carrier's defense is untouched")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.encumbranceOverloadedSlowsMovementAndWeakensDefense()
|
||||||
|
local game = Game.new(1)
|
||||||
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
"rngDeterminism", "mapDeterminism", "tilesRegistry", "fovKnownScene", "losSightLine",
|
"rngDeterminism", "mapDeterminism", "tilesRegistry", "fovKnownScene", "losSightLine",
|
||||||
"astarPathing", "combatResolution", "itemsAndEquipment", "affixes", "statusEffects",
|
"astarPathing", "combatResolution", "itemsAndEquipment", "affixes", "statusEffects",
|
||||||
|
|||||||
Reference in new issue
Block a user