Slightly more ECS spawner upgrades?

Not positive this is in the spirit, but we're figuring it out, kay?
This commit is contained in:
Sage Vaillancourt 2025-03-07 17:10:04 -05:00
parent 60461aa14f
commit d6c934a265
5 changed files with 116 additions and 43 deletions

View File

@ -3,6 +3,9 @@
-- This file is composed of, essentially, "base types" -- This file is composed of, essentially, "base types"
local SOME_TABLE <const> = {}
---@alias AnyComponent any
---@alias BitMask number ---@alias BitMask number
---@alias CanBeBounced { flat: XyPair, mult = XyPair } ---@alias CanBeBounced { flat: XyPair, mult = XyPair }
---@alias CanSpawn { entityToSpawn: Entity } ---@alias CanSpawn { entityToSpawn: Entity }
@ -10,7 +13,10 @@
---@alias Entity table ---@alias Entity table
---@alias InRelations Entity[] ---@alias InRelations Entity[]
---@alias InputState { receivedInputThisFrame: boolean, aJustPressed: boolean, bJustPressed: boolean, upJustPressed: boolean, downJustPressed: boolean, leftJustPressed: boolean, rightJustPressed: boolean } ---@alias InputState { receivedInputThisFrame: boolean, aJustPressed: boolean, bJustPressed: boolean, upJustPressed: boolean, downJustPressed: boolean, leftJustPressed: boolean, rightJustPressed: boolean }
---@alias ReplaceRelation { entityToModify: Entity, replacement: Replacement }
---@alias Replacement { key: string, value: AnyComponent }
---@alias RoundStateAction "end" | "start" ---@alias RoundStateAction "end" | "start"
---@alias Selectable { additions: Entity[] | nil, replacements: ReplaceRelation[] | nil, highlighted: boolean, navigateDown: Selectable | nil, navigateUp: Selectable | nil }
---@alias XyPair { x: number, y: number } ---@alias XyPair { x: number, y: number }
@ -19,7 +25,7 @@ T = {
number = 0, number = 0,
numberArray = { 1, 2, 3 }, numberArray = { 1, 2, 3 },
str = "", str = "",
marker = {}, marker = SOME_TABLE,
---@type fun(self) ---@type fun(self)
SelfFunction = function() end, SelfFunction = function() end,
--- Actor --- Actor
@ -29,28 +35,49 @@ T = {
mult = XyPair, mult = XyPair,
}, },
---@type pd_image ---@type pd_image
pd_image = {}, pd_image = SOME_TABLE,
---@type pd_font ---@type pd_font
pd_font = {}, pd_font = SOME_TABLE,
---@type AnyComponent
AnyComponent = SOME_TABLE,
---@type BitMask ---@type BitMask
BitMask = 0, BitMask = 0,
---@type CanBeBounced ---@type CanBeBounced
CanBeBounced = {}, CanBeBounced = SOME_TABLE,
---@type CanSpawn ---@type CanSpawn
CanSpawn = {}, CanSpawn = SOME_TABLE,
---@type Collision ---@type Collision
Collision = {}, Collision = SOME_TABLE,
---@type Entity ---@type Entity
Entity = {}, Entity = SOME_TABLE,
---@type InRelations ---@type InRelations
InRelations = {}, InRelations = SOME_TABLE,
---@type InputState ---@type InputState
InputState = {}, InputState = SOME_TABLE,
---@type ReplaceRelation
ReplaceRelation = SOME_TABLE,
---@type Replacement
Replacement = SOME_TABLE,
---@type RoundStateAction ---@type RoundStateAction
RoundStateAction = "start", RoundStateAction = "start",
---@type Selectable
Selectable = SOME_TABLE,
---@type XyPair ---@type XyPair
XyPair = {}, XyPair = SOME_TABLE,
} }
---@generic T ---@generic T
@ -60,6 +87,13 @@ function Maybe(t)
return { maybe = t } return { maybe = t }
end end
---@generic T
---@param t T
---@return T[]
function Arr(t)
return { arrOf = t }
end
TextStyle = { TextStyle = {
Inverted = "INVERTED", Inverted = "INVERTED",
Bordered = "BORDERED", Bordered = "BORDERED",

View File

@ -12,7 +12,7 @@ function t(name, type, value)
elseif type == "string" then elseif type == "string" then
value = "" value = ""
else else
value = "{}" value = "SOME_TABLE"
end end
end end
types[#types + 1] = { name = name, type = type, value = value } types[#types + 1] = { name = name, type = type, value = value }
@ -42,7 +42,7 @@ end
function dumpTypeObjects() function dumpTypeObjects()
local ret = "" local ret = ""
for _, v in ipairs(types) do for _, v in ipairs(types) do
local line = "\n ---@type " .. v.name .. "\n " .. v.name .. " = " .. v.value .. "," local line = "\n\n ---@type " .. v.name .. "\n " .. v.name .. " = " .. v.value .. ","
ret = ret .. line ret = ret .. line
end end
return ret return ret
@ -51,6 +51,8 @@ end
-- This file is composed of, essentially, "base types" -- This file is composed of, essentially, "base types"
local SOME_TABLE <const> = {}
!!(tMany({ !!(tMany({
Entity = "table", Entity = "table",
XyPair = "{ x: number, y: number }", XyPair = "{ x: number, y: number }",
@ -58,10 +60,15 @@ end
BitMask = "number", BitMask = "number",
CanBeBounced = "{ flat: XyPair, mult: XyPair }", CanBeBounced = "{ flat: XyPair, mult: XyPair }",
RoundStateAction = { '"end" | "start"', '"start"' }, RoundStateAction = { '"end" | "start"', '"start"' },
AnyComponent = "any",
CanSpawn = "{ entityToSpawn: Entity }", CanSpawn = "{ entityToSpawn: Entity }",
InRelations = "Entity[]", InRelations = "Entity[]",
CanBeBounced = "{ flat: XyPair, mult = XyPair }", CanBeBounced = "{ flat: XyPair, mult = XyPair }",
InputState = "{ receivedInputThisFrame: boolean, aJustPressed: boolean, bJustPressed: boolean, upJustPressed: boolean, downJustPressed: boolean, leftJustPressed: boolean, rightJustPressed: boolean }", InputState = "{ receivedInputThisFrame: boolean, aJustPressed: boolean, bJustPressed: boolean, upJustPressed: boolean, downJustPressed: boolean, leftJustPressed: boolean, rightJustPressed: boolean }",
Replacement = "{ key: string, value: AnyComponent }",
ReplaceRelation = "{ entityToModify: Entity, replacement: Replacement }",
Selectable = "{ additions: Entity[] | nil, replacements: ReplaceRelation[] | nil, highlighted: boolean, navigateDown: Selectable | nil, navigateUp: Selectable | nil }",
})) }))
T = { T = {
@ -69,7 +76,7 @@ T = {
number = 0, number = 0,
numberArray = { 1, 2, 3 }, numberArray = { 1, 2, 3 },
str = "", str = "",
marker = {}, marker = SOME_TABLE,
---@type fun(self) ---@type fun(self)
SelfFunction = function() end, SelfFunction = function() end,
--- Actor --- Actor
@ -79,9 +86,9 @@ T = {
mult = XyPair, mult = XyPair,
}, },
---@type pd_image ---@type pd_image
pd_image = {}, pd_image = SOME_TABLE,
---@type pd_font ---@type pd_font
pd_font = {}, pd_font = SOME_TABLE,
!!(dumpTypeObjects()) !!(dumpTypeObjects())
} }
@ -92,6 +99,13 @@ function Maybe(t)
return { maybe = t } return { maybe = t }
end end
---@generic T
---@param t T
---@return T[]
function Arr(t)
return { arrOf = t }
end
TextStyle = { TextStyle = {
Inverted = "INVERTED", Inverted = "INVERTED",
Bordered = "BORDERED", Bordered = "BORDERED",

View File

@ -1,17 +1,35 @@
---@alias MenuItem { onSelect: fun(), highlighted: boolean, navigateDown: MenuItem | nil, navigateUp: MenuItem | nil } ---@param relation ReplaceRelation
---@param world World
local function applyReplacementRelation(relation, world)
printTable(relation.entityToModify)
relation.entityToModify[relation.replacement.key] = relation.replacement.value
world:addEntity(relation.entityToModify)
printTable(relation.entityToModify)
end
---@type MenuItem[] menuController = filteredSystem("menuController", { menuItems = Arr(T.Selectable), inputState = T.InputState }, function(e, _, system)
local MenuItems = {}
menuController = filteredSystem("menuController", { menuItems = MenuItems, inputState = T.InputState }, function(e, _, system)
for _, menuItem in pairs(e.menuItems) do for _, menuItem in pairs(e.menuItems) do
if menuItem.highlighted then if menuItem.highlighted then
if e.inputState.aJustPressed then if e.inputState.aJustPressed then
menuItem.onSelect(system.world) -- TODO: That's not very ECS of you! -- Prepare to remove the menu and all menu items
system.world:removeEntity(e)
for _, item in pairs(e.menuItems) do for _, item in pairs(e.menuItems) do
system.world:removeEntity(item) system.world:removeEntity(item)
end end
system.world:removeEntity(e)
-- TODO: Larger menu that stays open for more purchases before the next round
world:addEntity({ roundAction = "start" })
if menuItem.replacements then
for _, v in ipairs(menuItem.replacements) do
applyReplacementRelation(v, system.world)
end
end
if menuItem.additions then
for _, v in ipairs(menuItem.additions) do
system.world:addEntity(v)
end
end
end end
if e.inputState.downJustPressed and menuItem.navigateDown then if e.inputState.downJustPressed and menuItem.navigateDown then

View File

@ -102,6 +102,7 @@ roundSystem = filteredSystem("round", { roundAction = T.RoundStateAction, positi
system.world:removeEntity(collectable) system.world:removeEntity(collectable)
end end
---@type SpawnerUpgrade[]
local availableUpgrades = Utils.getNDifferentValues(getAvailableSpawnerUpgrades(), 3) local availableUpgrades = Utils.getNDifferentValues(getAvailableSpawnerUpgrades(), 3)
-- Sorting from shortest to longest sort of makes them look like a bun? -- Sorting from shortest to longest sort of makes them look like a bun?
table.sort(availableUpgrades, function(a, b) table.sort(availableUpgrades, function(a, b)
@ -119,8 +120,9 @@ roundSystem = filteredSystem("round", { roundAction = T.RoundStateAction, positi
i = i + 1 i = i + 1
local collX, collY = 75, 21 local collX, collY = 75, 21
y = y - collY - 15 - 15 y = y - collY - 15 - 15
---@type Selectable
local upgradeEntity = { local upgradeEntity = {
onSelect = upgrade.apply, replacements = { upgrade.replace },
drawAsText = { drawAsText = {
text = upgrade.name, text = upgrade.name,
style = TextStyle.Inverted, style = TextStyle.Inverted,

View File

@ -101,38 +101,43 @@ function addAllSpawners(world)
}) })
end end
---@alias Upgrade { name: string, apply = fun() } ---@alias SpawnerUpgrade { name: string, replace: ReplaceRelation }
---@return Upgrade[] ---@return SpawnerUpgrade[]
function getAvailableSpawnerUpgrades() function getAvailableSpawnerUpgrades()
---@type SpawnerUpgrade[]
local upgrades = {} local upgrades = {}
for _, spawner in pairs(spawnerSystem.entities) do for _, spawner in pairs(spawnerSystem.entities) do
if spawner.hasUpgradeSpeed then -- if spawner.hasUpgradeSpeed then
-- upgrades[#upgrades + 1] = { hasUpgradeSpeed = spawner.hasUpgradeSpeed } -- upgrades[#upgrades + 1] = { hasUpgradeSpeed = spawner.hasUpgradeSpeed }
end -- end
if spawner.canSpawn.entityToSpawn.score then local entityToSpawn = spawner.canSpawn.entityToSpawn
local name = "Double " .. spawner.name .. " value" if entityToSpawn.score then
upgrades[#upgrades + 1] = { upgrades[#upgrades + 1] = {
name = name, name = "Double " .. spawner.name .. " value",
apply = function(world) replace = {
print("Applying " .. name) entityToModify = entityToSpawn,
spawner.canSpawn.entityToSpawn.score = spawner.canSpawn.entityToSpawn.score * 2 replacement = {
world:addEntity({ roundAction = "start" }) key = "score",
end, value = entityToSpawn.score * 2,
},
},
} }
end end
assert(spawner.odds, "Expected all spawners to have an `odds` field!") assert(spawner.odds, "Expected all spawners to have an `odds` field!")
local name = "Double " .. spawner.name .. " frequency"
upgrades[#upgrades + 1] = { upgrades[#upgrades + 1] = {
name = name, name = "Double " .. spawner.name .. " frequency",
apply = function(world) replace = {
print("Applying " .. name) entityToModify = entityToSpawn,
spawner.odds = spawner.odds * 2 replacement = {
world:addEntity({ roundAction = "start" }) key = "odds",
end, value = entityToSpawn.odds,
}
},
} }
end end
return upgrades return upgrades
end end