test: cover tests.gameAwardKillOnANemesisGrantsBonusXpAndBountyGoldAn...
This commit is contained in:
1 parent
2163658381
commit
c2c0a4c962
1 file changed
+173
+173
@@ -10509,6 +10509,179 @@ end
|
|||||||
|
|
||||||
function tests.gameAscendCarriesEveryLivingAllyBackOntoThePreviousFloorToo()
|
function tests.gameAscendCarriesEveryLivingAllyBackOntoThePreviousFloorToo()
|
||||||
local game = stagedGame(1, arena(21, 11), 3, 6)
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
game.player.x, game.player.y = game.level.downX, game.level.downY
|
||||||
|
game:descend()
|
||||||
|
eq(game.depth, 2, "now on the second floor")
|
||||||
|
local golem = Companions.summon(game, "golem")
|
||||||
|
local hireling = Mercenaries.hire(game, "sellsword")
|
||||||
|
ok(golem ~= nil and hireling ~= nil, "both allies bond on the second floor")
|
||||||
|
local descendLevel = game.level
|
||||||
|
|
||||||
|
game.player.x, game.player.y = game.level.upX, game.level.upY
|
||||||
|
ok(game:ascend(), "ascending succeeds")
|
||||||
|
eq(game.depth, 1, "back on the first floor")
|
||||||
|
ok(game:hasCompanion(), "the companion follows back up the stairs")
|
||||||
|
ok(game:hasHireling(), "the hireling follows back up the stairs too")
|
||||||
|
|
||||||
|
local leftBehind = 0
|
||||||
|
for _, entity in ipairs(descendLevel.entities) do
|
||||||
|
if entity.kind == "companion" or entity.kind == "hireling" then leftBehind = leftBehind + 1 end
|
||||||
|
end
|
||||||
|
eq(leftBehind, 0, "neither ally is stranded on the floor just climbed away from")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.gameAwardKillOnANemesisGrantsBonusXpAndBountyGoldAndClearsTheHunt()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 6)
|
||||||
|
game.nemesis = { species = "orc", grudge = 3, hpFraction = 1 }
|
||||||
|
local hunter = Nemesis.spawn(game.nemesis, 1, 4, 6, 1)
|
||||||
|
hunter.hp = 1
|
||||||
|
game.level.entities = { hunter }
|
||||||
|
local xpBefore, goldBefore = game.player.xp, game.player.gold
|
||||||
|
game:playerAttack(hunter)
|
||||||
|
ok(game.player.xp > xpBefore or game.player.level > 1, "felling the nemesis grants xp on top of its species reward")
|
||||||
|
eq(game.player.gold, goldBefore + Nemesis.bountyGold(3), "felling the nemesis pays out its grudge-scaled bounty gold")
|
||||||
|
eq(game.nemesis, nil, "the hunt is over once the nemesis is actually killed")
|
||||||
|
ok(contains(table.concat(game.log:recent(5), " "), "hunt is over"), "the kill is logged as ending the hunt")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.nemesisFieldsSurviveEntityAndGameSerialization()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 5, 5)
|
||||||
|
game.nemesis = { species = "orc", grudge = 3, hpFraction = 0.75 }
|
||||||
|
local hunter = Nemesis.spawn(game.nemesis, 1, 6, 5, 1)
|
||||||
|
game.level.entities = { hunter }
|
||||||
|
|
||||||
|
local restoredLevel = Level.fromData(game.level:toData())
|
||||||
|
eq(restoredLevel.entities[1].nemesis, true, "the nemesis flag survives a level round trip")
|
||||||
|
eq(restoredLevel.entities[1].nemesisGrudge, 3, "the nemesis's grudge survives a level round trip")
|
||||||
|
|
||||||
|
local restoredGame = Game.fromData(game:toData())
|
||||||
|
eq(restoredGame.nemesis.species, "orc", "the pursuing nemesis descriptor survives a game round trip")
|
||||||
|
eq(restoredGame.nemesis.grudge, 3, "the descriptor's grudge survives a game round trip")
|
||||||
|
eq(restoredGame.nemesis.hpFraction, 0.75, "the descriptor's carried hp fraction survives a game round trip")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.factionsAreRivalsChecksBothDirectionsAndExcludesSameFactionAndNil()
|
||||||
|
ok(Factions.areRivals(Factions.GOBLINOID, Factions.ORCISH), "goblinoid and orcish are a listed rivalry")
|
||||||
|
ok(Factions.areRivals(Factions.ORCISH, Factions.GOBLINOID), "the rivalry check reads either direction")
|
||||||
|
ok(not Factions.areRivals(Factions.GOBLINOID, Factions.GOBLINOID), "a faction is never its own rival")
|
||||||
|
ok(not Factions.areRivals(Factions.MERCHANT, Factions.DRAKE), "an unlisted pair is not a rivalry")
|
||||||
|
ok(not Factions.areRivals(nil, Factions.ORCISH), "a nil faction on either side never counts as a rival")
|
||||||
|
ok(not Factions.areRivals(Factions.GOBLINOID, nil), "a nil faction on either side never counts as a rival")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingTargetPicksTheNearestVisibleRivalOverACloserNonRival()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
local goblin = Monsters.create(Monsters.byKey.goblin, 1, 10, 6, 1)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 2, 12, 6, 1)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 3, 9, 6, 1)
|
||||||
|
game.level.entities = { goblin, orc, rat }
|
||||||
|
local target = Infighting.target(game, goblin)
|
||||||
|
eq(target.id, orc.id, "the goblin's rival target is the orc, not the nearer but unrelated rat")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingTargetIgnoresARivalBeyondSightRange()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
local goblin = Monsters.create(Monsters.byKey.goblin, 1, 3, 6, 1)
|
||||||
|
local farOrc = Monsters.create(Monsters.byKey.orc, 2, 19, 6, 1)
|
||||||
|
game.level.entities = { goblin, farOrc }
|
||||||
|
ok(Infighting.target(game, goblin) == nil, "a rival far beyond sight range is not a target")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingTargetIgnoresARivalBehindAWallEvenWithinSightRange()
|
||||||
|
local map = Map.new(21, 11)
|
||||||
|
for y = 2, 9 do
|
||||||
|
for x = 2, 9 do map:set(x, y, Map.FLOOR) end
|
||||||
|
for x = 12, 19 do map:set(x, y, Map.FLOOR) end
|
||||||
|
end
|
||||||
|
local level = Level.new({
|
||||||
|
depth = 1, generator = "arena", map = map,
|
||||||
|
entities = {}, floorItems = {}, traps = {}, lights = {}, dark = false, explored = {},
|
||||||
|
upX = 2, upY = 2, downX = 19, downY = 9,
|
||||||
|
})
|
||||||
|
local game = stagedGame(1, level, 2, 2)
|
||||||
|
local goblin = Monsters.create(Monsters.byKey.goblin, 1, 9, 5, 1)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 2, 12, 5, 1)
|
||||||
|
game.level.entities = { goblin, orc }
|
||||||
|
ok(Infighting.target(game, goblin) == nil,
|
||||||
|
"a rival on the far side of a solid wall is not a target despite being close in raw distance")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingTargetIgnoresNonRivalsWithoutDiscord()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
local goblin = Monsters.create(Monsters.byKey.goblin, 1, 10, 6, 1)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 2, 11, 6, 1)
|
||||||
|
game.level.entities = { goblin, rat }
|
||||||
|
ok(Infighting.target(game, goblin) == nil, "an unrelated species is never a target on its own")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingTargetUnderDiscordPicksNearestCreatureOfAnyKindIncludingACompanion()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 10, 6, 1)
|
||||||
|
Status.apply(orc, Status.DISCORD, 5, 1)
|
||||||
|
local companion = Entity.new({
|
||||||
|
id = 2, x = 11, y = 6, glyph = "d", name = "wolf", kind = "companion",
|
||||||
|
hp = 10, maxHp = 10, attack = 2, defense = 0, speed = 100,
|
||||||
|
})
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 3, 15, 6, 1)
|
||||||
|
game.level.entities = { orc, companion, rat }
|
||||||
|
local target = Infighting.target(game, orc)
|
||||||
|
eq(target.id, companion.id,
|
||||||
|
"a discorded monster attacks the nearest creature of any kind, even a companion, over a farther non-rival")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingTargetReturnsNilOnceDiscordHasExpired()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 10, 6, 1)
|
||||||
|
local rat = Monsters.create(Monsters.byKey.rat, 2, 11, 6, 1)
|
||||||
|
game.level.entities = { orc, rat }
|
||||||
|
ok(Infighting.target(game, orc) == nil, "without discord an orc has no quarrel with a nearby rat")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingStrikeOnAPlainMonsterSpawnsACorpseButAwardsThePlayerNothing()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
local goblin = Monsters.create(Monsters.byKey.goblin, 1, 10, 6, 1)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 2, 11, 6, 1)
|
||||||
|
orc.hp, orc.maxHp = 1, 1
|
||||||
|
game.level.entities = { goblin, orc }
|
||||||
|
local xpBefore = game.player.xp
|
||||||
|
local killsBefore = game.stats.kills
|
||||||
|
Infighting.strike(game, goblin, orc)
|
||||||
|
ok(not orc:isAlive(), "the orc dies to the goblin's blow")
|
||||||
|
eq(game.player.xp, xpBefore, "the player earns no xp for a kill it did not land")
|
||||||
|
eq(game.stats.kills, killsBefore, "the run's kill counter only tracks the player's own kills")
|
||||||
|
eq(#game.level.corpses, 1, "the fallen orc still leaves a corpse behind for scavenging or reanimation")
|
||||||
|
ok(contains(game.log:last(), "dies"), "the death is still logged")
|
||||||
|
end
|
||||||
|
|
||||||
|
function tests.infightingStrikeThatKillsACompanionRoutesThroughTheNormalAllyDeathMessage()
|
||||||
|
local game = stagedGame(1, arena(21, 11), 3, 3)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 1, 10, 6, 1)
|
||||||
|
local wolf = Entity.new({
|
||||||
|
id = 2, x = 11, y = 6, glyph = "d", name = "wolf", kind = "companion",
|
||||||
|
hp = 1, maxHp = 10, attack = 2, defense = 0, speed = 100,
|
||||||
|
})
|
||||||
|
game.level.entities = { orc, wolf }
|
||||||
|
Infighting.strike(game, orc, wolf)
|
||||||
|
ok(contains(game.log:last(), "falls"), "a companion killed by infighting dies with the same message as any other death")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Same gap as companionActAttackingAnAdjacentMonsterEmitsNoise... and its
|
||||||
|
-- hireling/thrall siblings, but here on neither side of the fight is a
|
||||||
|
-- player-aligned ally at all: two monsters brawling among themselves (a
|
||||||
|
-- rivalry, or one of them discorded) were exactly as silent as a companion's
|
||||||
|
-- own melee, despite Infighting.strike running the very same Combat.attack
|
||||||
|
-- every other fight in the engine does. A dormant third monster standing
|
||||||
|
-- nearby but uninvolved never had a chance to overhear either kind of fight.
|
||||||
|
function tests.infightingStrikeEmitsNoiseThatCanStirADormantBystanderNotInvolvedInTheFight()
|
||||||
|
local stirred = false
|
||||||
|
for seed = 1, 200 do
|
||||||
|
local game = stagedGame(seed, arena(21, 11), 3, 3)
|
||||||
|
local goblin = Monsters.create(Monsters.byKey.goblin, 1, 10, 6, 1)
|
||||||
|
local orc = Monsters.create(Monsters.byKey.orc, 2, 11, 6, 1)
|
||||||
|
local bystander = Monsters.create(Monsters.byKey.rat, 3, 14, 6, 1)
|
||||||
|
bystander.awareness = Stealth.DORMANT
|
||||||
|
game.level.entities = { goblin, orc, bystander }
|
||||||
|
Infighting.strike(game, goblin, orc)
|
||||||
end
|
end
|
||||||
|
|
||||||
local order = {
|
local order = {
|
||||||
|
|||||||
Reference in new issue
Block a user