polf/systems/ballEffects.lua

174 lines
5.7 KiB
Lua

local gridElements = filteredSystem("gridElements", { gridPosition = T.XyPair, effectsToApply = T.AnyComponent })
filteredSystem("timers", { timerSec = T.number, callback = T.SelfFunction }, function(e, dt, system)
e.timerSec = e.timerSec - dt
if e.timerSec < 0 then
e:callback()
system.world:removeEntity(e)
end
end)
function math.sign(n)
return n > 0 and 1 or n < 0 and -1 or 0
end
RoundSystem = filteredSystem("rounds", { roundState = T.str }, function(e)
-- print("roundState: " .. e.roundState)
end)
---@alias RoundState "active" | "animating" | "end"
---@param state RoundState
function RoundSystem:remove(state)
for _, round in pairs(self.entities) do
if round.roundState == state then
self.world:removeEntity(round)
end
end
end
---@param state RoundState
function RoundSystem:hasState(state)
for _, round in pairs(self.entities) do
if round.roundState == state then
return true
end
end
return false
end
---@param n number
---@param nToSlowBy number
---@return number slowedValue
local function slowBy(n, nToSlowBy)
if math.abs(n) < math.abs(nToSlowBy) then
return 0
end
return n - (math.sign(n) * nToSlowBy)
end
---
---@param n number
---@param nToSlowTo number
---@return number slowedValue
local function slowTo(n, nToSlowTo)
if math.abs(n) < math.abs(nToSlowTo) then
return 0
end
return math.sign(n) * nToSlowTo
end
---@class BallEffects
---@field gridPosition nil | XyPair
---@field slowsTo nil | XyPair
---@field slowsBy nil | XyPair
---@field movement nil | XyPair
---@field fliesFor nil | number
---@field teleportTo nil | BallEffects
---@type BallEffects
local BallEffects = {}
local activeBallEffects = filteredSystem(
"activeBallEffects",
{ ballEffects = BallEffects, gridPosition = T.XyPair, position = T.XyPair },
function(e, _, system)
local gridPosition, effects = e.gridPosition, e.ballEffects
if effects.fliesFor == nil then
-- Search for new effects from the current tile
for _, gridElement in pairs(gridElements.entities) do
if gridPosition.x == gridElement.gridPosition.x and gridPosition.y == gridElement.gridPosition.y then
-- More direct-mutation-y than I'd like,
-- but offers a simple way to overwrite existing effects.
-- We're "setting InRelations" :D
for key, value in pairs(gridElement.effectsToApply) do
effects[key] = value
end
if gridElement.spriteAfterEffect then
gridElement.drawAsSprite = gridElement.spriteAfterEffect
gridElement.spriteAfterEffect = nil
end
gridElement.effectsToApply = nil
system.world:addEntity(gridElement)
end
end
else
effects.fliesFor = effects.fliesFor - 1
if effects.fliesFor == 0 then
effects.fliesFor = nil
end
end
--------------------------------------------------------
-- Apply any effects currently connected to this ball --
--------------------------------------------------------
if effects.teleportTo ~= nil then
local targetGridPos = effects.teleportTo.gridPosition
gridPosition.x = targetGridPos.x
gridPosition.y = targetGridPos.y
-- Jump to position directly, instead of animating there gradually
e.position = PositionAtGridXy(gridPosition.x, gridPosition.y)
-- Deactivate receiving teleporter
effects.teleportTo.effectsToApply = {}
effects.teleportTo = nil
else
if effects.movement ~= nil then
if effects.slowsBy ~= nil then
effects.movement.x = slowBy(effects.movement.x, effects.slowsBy.x)
effects.movement.y = slowBy(effects.movement.y, effects.slowsBy.y)
effects.slowsBy = nil
end
if effects.slowsTo ~= nil then
effects.movement.x = slowTo(effects.movement.x, effects.slowsTo.x)
effects.movement.y = slowTo(effects.movement.y, effects.slowsTo.y)
effects.slowsTo = nil
end
if effects.movement.x == 0 and effects.movement.y == 0 then
effects.movement = nil
else
gridPosition.x = gridPosition.x + math.sign(effects.movement.x)
gridPosition.y = gridPosition.y + math.sign(effects.movement.y)
effects.movement.x = effects.movement.x - math.sign(effects.movement.x)
effects.movement.y = effects.movement.y - math.sign(effects.movement.y)
end
end
end
if effects.endOfRound ~= nil then
effects.endOfRound = nil
system.world:addEntity({ roundState = "end" })
system.world:removeEntity(e)
-- print("End of round")
return
end
for _, _ in pairs(effects) do
-- Return if there are any effects left
-- print("Setting roundState to animating...")
system.world:addEntity({ roundState = "animating" })
return
end
-- print("End of round")
system.world:addEntity({ roundState = "end" })
system.world:removeEntity(e)
end
)
function activeBallEffects:preProcess(dt)
if RoundSystem:hasState("animating") then
return tiny.SKIP_PROCESS
end
if RoundSystem:hasState("active") then
return
end
return tiny.SKIP_PROCESS
end