103 lines
4.8 KiB
Lua
103 lines
4.8 KiB
Lua
-- Herb-based potion brewing, layered on top of items.lua's existing potion
|
|
-- catalog rather than inventing a second one: a cauldron turns two foraged
|
|
-- herbs into the same potions rollItem already scatters as loot, so a
|
|
-- brewed potion drinks, throws (throwing.lua) and identifies exactly like a
|
|
-- found one. Recipes are fixed data, the same way crafting.lua's elemental
|
|
-- riders are fixed - the uncertainty here is not "what does this pair do"
|
|
-- but whether two ill-matched herbs curdle instead of brewing cleanly. See
|
|
-- Game:brewAt for how a curdle is resolved against the brewer.
|
|
|
|
local Items = require("items")
|
|
|
|
local Alchemy = {}
|
|
|
|
Alchemy.SUNPETAL = "sunpetal"
|
|
Alchemy.BLOODROOT = "bloodroot"
|
|
Alchemy.EMBERLEAF = "emberleaf"
|
|
Alchemy.FROSTMOSS = "frostmoss"
|
|
Alchemy.NIGHTCAP = "nightcap"
|
|
Alchemy.MOONBELL = "moonbell"
|
|
|
|
-- Fixed order so a given rng draw always names the same herb. New herbs
|
|
-- append at the end (see builder.lua's own comment on Alchemy.order) so an
|
|
-- existing seed's earlier picks never change which herb they name.
|
|
Alchemy.order = {
|
|
Alchemy.BLOODROOT, Alchemy.EMBERLEAF, Alchemy.FROSTMOSS, Alchemy.NIGHTCAP, Alchemy.SUNPETAL,
|
|
Alchemy.MOONBELL,
|
|
}
|
|
|
|
Alchemy.names = {
|
|
[Alchemy.SUNPETAL] = "sunpetal",
|
|
[Alchemy.BLOODROOT] = "bloodroot",
|
|
[Alchemy.EMBERLEAF] = "emberleaf",
|
|
[Alchemy.FROSTMOSS] = "frostmoss",
|
|
[Alchemy.NIGHTCAP] = "nightcap",
|
|
[Alchemy.MOONBELL] = "moonbell",
|
|
}
|
|
|
|
local CURDLE = { curdle = true }
|
|
|
|
-- Canonical order-independent key for a herb pair: the two herb keys sorted
|
|
-- and joined, so brewing (A, B) and (B, A) always land on the same recipe.
|
|
local function pairKey(a, b)
|
|
if a > b then a, b = b, a end
|
|
return a .. "+" .. b
|
|
end
|
|
Alchemy.pairKey = pairKey
|
|
|
|
-- Same-herb pairs concentrate that herb's own aspect; cross pairs blend two
|
|
-- aspects into a shared potion, except the pairings whose aspects outright
|
|
-- oppose each other (light versus shade, fire versus frost, day versus
|
|
-- dream), which curdle instead of brewing.
|
|
Alchemy.recipes = {
|
|
[pairKey(Alchemy.SUNPETAL, Alchemy.SUNPETAL)] = { effect = "heal", power = 18 },
|
|
[pairKey(Alchemy.SUNPETAL, Alchemy.BLOODROOT)] = { effect = "heal", power = 10 },
|
|
[pairKey(Alchemy.SUNPETAL, Alchemy.EMBERLEAF)] = { effect = "haste" },
|
|
[pairKey(Alchemy.SUNPETAL, Alchemy.FROSTMOSS)] = { effect = "fortify" },
|
|
[pairKey(Alchemy.SUNPETAL, Alchemy.NIGHTCAP)] = CURDLE,
|
|
[pairKey(Alchemy.BLOODROOT, Alchemy.BLOODROOT)] = { effect = "strength" },
|
|
[pairKey(Alchemy.BLOODROOT, Alchemy.EMBERLEAF)] = { effect = "strength" },
|
|
[pairKey(Alchemy.BLOODROOT, Alchemy.FROSTMOSS)] = { effect = "fortify" },
|
|
[pairKey(Alchemy.BLOODROOT, Alchemy.NIGHTCAP)] = { effect = "poison", power = 4 },
|
|
[pairKey(Alchemy.EMBERLEAF, Alchemy.EMBERLEAF)] = { effect = "haste" },
|
|
[pairKey(Alchemy.EMBERLEAF, Alchemy.FROSTMOSS)] = CURDLE,
|
|
[pairKey(Alchemy.EMBERLEAF, Alchemy.NIGHTCAP)] = { effect = "poison", power = 5 },
|
|
[pairKey(Alchemy.FROSTMOSS, Alchemy.FROSTMOSS)] = { effect = "fortify" },
|
|
[pairKey(Alchemy.FROSTMOSS, Alchemy.NIGHTCAP)] = { effect = "poison", power = 5 },
|
|
[pairKey(Alchemy.NIGHTCAP, Alchemy.NIGHTCAP)] = { effect = "poison", power = 7 },
|
|
-- Moonbell's own aspect is dream-fog, so concentrating it addles the
|
|
-- brewer's own mind rather than anyone else's - the same "own aspect
|
|
-- turned inward" shape as every other same-herb pair above. Sunlight is
|
|
-- the one aspect it outright opposes (wakeful day versus dreaming night,
|
|
-- the same shape as sunpetal/nightcap's light-versus-shade curdle above),
|
|
-- so that pairing curdles instead of brewing.
|
|
[pairKey(Alchemy.MOONBELL, Alchemy.MOONBELL)] = { effect = "confuse" },
|
|
[pairKey(Alchemy.SUNPETAL, Alchemy.MOONBELL)] = CURDLE,
|
|
[pairKey(Alchemy.BLOODROOT, Alchemy.MOONBELL)] = { effect = "clarity" },
|
|
[pairKey(Alchemy.EMBERLEAF, Alchemy.MOONBELL)] = { effect = "blind" },
|
|
[pairKey(Alchemy.FROSTMOSS, Alchemy.MOONBELL)] = { effect = "levitate" },
|
|
[pairKey(Alchemy.NIGHTCAP, Alchemy.MOONBELL)] = { effect = "poison", power = 6 },
|
|
}
|
|
|
|
function Alchemy.herb(key)
|
|
return { kind = Items.HERB, herb = key, name = Alchemy.names[key] .. " herb", glyph = ";" }
|
|
end
|
|
|
|
-- The fixed outcome for brewing herbA with herbB together, order
|
|
-- independent. Returns nil only when either key names no known herb.
|
|
function Alchemy.lookup(herbA, herbB)
|
|
if not Alchemy.names[herbA] or not Alchemy.names[herbB] then return nil end
|
|
return Alchemy.recipes[pairKey(herbA, herbB)]
|
|
end
|
|
|
|
-- Resolves a completed brew into a fresh potion item, or (nil, "curdle") for
|
|
-- an opposed pairing - the caller decides what a curdle does to the brewer.
|
|
function Alchemy.brew(herbA, herbB)
|
|
local recipe = Alchemy.lookup(herbA, herbB)
|
|
if not recipe then return nil, "unknown herb" end
|
|
if recipe.curdle then return nil, "curdle" end
|
|
return Items.potionOf(recipe.effect, recipe.power)
|
|
end
|
|
|
|
return Alchemy
|