test: cover tests.alchemyMoonbellPairedWithItselfConcentratesIntoConf...

This commit is contained in:
dualfroz committed 2026-09-13 20:55:11 +02:00
1 parent 281fe36e73
commit 6f581d988e
1 file changed
+81
+81
View File
@@ -14488,6 +14488,87 @@ end
-- loot, a trap, or a spell before this, a gap flagged (and deliberately not
-- closed, since the existing five-herb grid was already fully assigned)
-- across several earlier sessions today. Its own pair concentrates its
-- dream-fog aspect into confusion, the same "own aspect turned inward" shape
-- as every other same-herb recipe.
function tests.alchemyMoonbellPairedWithItselfConcentratesIntoConfusion()
local potion = Alchemy.brew(Alchemy.MOONBELL, Alchemy.MOONBELL)
eq(potion.effect, "confuse", "a doubled moonbell brews its own dream-fog aspect")
end
-- Sunpetal (wakeful daylight) is the one aspect moonbell (dreaming night)
-- outright opposes, the same shape as the pre-existing sunpetal/nightcap
-- (light versus shade) and emberleaf/frostmoss (fire versus frost) curdles.
function tests.alchemyMoonbellPairedWithSunpetalCurdlesOnTheDayVersusDreamOpposition()
local potion, reason = Alchemy.brew(Alchemy.SUNPETAL, Alchemy.MOONBELL)
eq(potion, nil, "day and dream herbs curdle rather than brewing a potion")
eq(reason, "curdle", "a curdled moonbell brew names its failure like any other opposed pair")
end
function tests.alchemyMoonbellPairedWithBloodrootBrewsClarity()
local potion = Alchemy.brew(Alchemy.BLOODROOT, Alchemy.MOONBELL)
eq(potion.effect, "clarity", "blood grounds the dreaming mind into clarity instead of confusion")
eq(potion.power, 30, "an unspecified recipe power falls back to the catalog default for its effect")
end
function tests.alchemyMoonbellPairedWithEmberleafBrewsBlindness()
local potion = Alchemy.brew(Alchemy.EMBERLEAF, Alchemy.MOONBELL)
eq(potion.effect, "blind", "fire's smoke thickened by dream-fog brews blindness")
end
function tests.alchemyMoonbellPairedWithFrostmossBrewsLevitation()
local potion = Alchemy.brew(Alchemy.FROSTMOSS, Alchemy.MOONBELL)
eq(potion.effect, "levitate", "frost's lightness carried by dream-fog brews levitation")
end
function tests.alchemyMoonbellPairedWithNightcapBrewsAStrongerPoisonThanEitherHerbAlone()
local blended = Alchemy.brew(Alchemy.NIGHTCAP, Alchemy.MOONBELL)
eq(blended.effect, "poison", "two shade-aspected herbs still blend into poison, like nightcap's other cross pairs")
ok(blended.power > Alchemy.recipes[Alchemy.pairKey(Alchemy.BLOODROOT, Alchemy.NIGHTCAP)].power,
"moonbell's nightcap blend is stronger than nightcap's weakest existing poison blend")
ok(blended.power < Alchemy.recipes[Alchemy.pairKey(Alchemy.NIGHTCAP, Alchemy.NIGHTCAP)].power,
"moonbell's nightcap blend still falls short of concentrated nightcap's own poison")
end
-- The five pre-existing herbs' own 15 recipes are untouched data (see
-- alchemy.lua's own comment on why moonbell appends rather than inserts) -
-- this pins the two still-standing curdles so a future change to the new
-- pairings above could never silently perturb them.
function tests.alchemyAddingMoonbellLeftEveryPreExistingRecipeUntouched()
eq(Alchemy.brew(Alchemy.SUNPETAL, Alchemy.SUNPETAL).power, 18, "concentrated sunpetal still heals for its original power")
local potion, reason = Alchemy.brew(Alchemy.SUNPETAL, Alchemy.NIGHTCAP)
eq(potion, nil, "sunpetal and nightcap still curdle")
eq(reason, "curdle", "the pre-existing curdle still names its failure the same way")
eq(Alchemy.brew(Alchemy.EMBERLEAF, Alchemy.FROSTMOSS), nil, "emberleaf and frostmoss still curdle too")
eq(Alchemy.brew(Alchemy.NIGHTCAP, Alchemy.NIGHTCAP).power, 7, "concentrated nightcap still brews its original poison power")
end
-- Exercises the full Game:brewAt pipeline (cauldron gating, inventory
-- spending, Identify.reveal) with the new herb, not just Alchemy.brew in
-- isolation - the unit-level recipe tests above already proved the fixed
-- outcomes; this proves the interactive path a player actually uses reaches
-- them unchanged.
function tests.gameBrewAtCanBrewAMoonbellPairingAtACauldron()
local game = stagedGame(1, arena(21, 11), 5, 5)
game.level.cauldrons = { { x = 5, y = 5 } }
game.player.inventory = { Alchemy.herb(Alchemy.MOONBELL), Alchemy.herb(Alchemy.FROSTMOSS) }
ok(game:brewAt(1, 2), "brewing moonbell with frostmoss 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.effect, "levitate", "the brewed potion matches moonbell/frostmoss's fixed recipe")
ok(Identify.isKnown(game.identify, brewed), "brewing a moonbell potion yourself identifies its type for free, like any other brew")
end
function tests.buildersOccasionallyRollAMoonbellHerbAsForagingLoot()
local found
for seed = 1, 200 do
local level = Builder.build(1, Rng.new(seed), {})
for _, ground in ipairs(level.floorItems) do
if ground.item.kind == Items.HERB and ground.item.herb == Alchemy.MOONBELL then found = ground.item end
end
if found then break end
end
ok(found ~= nil, "a moonbell herb eventually turns up in the entrance-floor foraging loot across a handful of seeds")
eq(found.name, "moonbell herb", "a foraged moonbell herb carries its plain, unmasked name like any other herb")
end
local order = {