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 slowsTo nil | XyPair ---@field slowsBy nil | XyPair ---@field movement nil | XyPair ---@field fliesFor nil | number ---@type BallEffects local BallEffects = {} local activeBallEffects = filteredSystem( "activeBallEffects", { ballEffects = BallEffects, gridPosition = 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.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 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" }) -- system.world:removeEntity(e) 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