diff --git a/main.lua b/main.lua index 0fb055f78..378325151 100644 --- a/main.lua +++ b/main.lua @@ -242,6 +242,9 @@ RudeBusterBurst = require("src.engine.game.effects.rudebusterburst") Shop = require("src.engine.game.shop") Shopkeeper = require("src.engine.game.shop.shopkeeper") +Border = require("src.engine.border") +ImageBorder = require("src.engine.imageborder") + GameOver = require("src.engine.game.gameover") Legend = require("src.engine.game.legend") diff --git a/mods/_testmod/scripts/borders/spinnysquare.lua b/mods/_testmod/scripts/borders/spinnysquare.lua new file mode 100644 index 000000000..81b7bfa41 --- /dev/null +++ b/mods/_testmod/scripts/borders/spinnysquare.lua @@ -0,0 +1,41 @@ +---@class Border.spinnysquare: Border +local SpinnySquare, super = Class(Border) + +function SpinnySquare:init() + super.init(self) +end + +function SpinnySquare:drawRect(max_depth, white) + if max_depth < 0 then return end + love.graphics.push("all") + if white then + Draw.setColor(1,1,1) + else + Draw.setColor(0.2,0.2,0.2) + end + love.graphics.scale( + Utils.clampMap( + math.sin(Kristal.getTime()), + -1, 1, 0.6, 0.93 + ) + ) + love.graphics.rotate(math.rad(20)) + love.graphics.rectangle("fill", -1000*BORDER_SCALE, -1000*BORDER_SCALE, 1000*2*BORDER_SCALE, 1000*2*BORDER_SCALE) + self:drawRect(max_depth - 1, not white) + love.graphics.pop() +end + +function SpinnySquare:draw() + love.graphics.push("all") + love.graphics.translate(1920*0.5*BORDER_SCALE, 1080*0.5*BORDER_SCALE) + love.graphics.scale(2) + love.graphics.rotate(math.rad(Kristal.getTime() * 20)) + + self:drawRect(20, true) + love.graphics.pop() + -- TODO: find a better way to add the fading + Draw.setColor(COLORS.black, 1-BORDER_ALPHA) + love.graphics.rectangle("fill", -love.graphics.getWidth(), -love.graphics.getHeight(), love.graphics.getWidth()*2, love.graphics.getHeight()*2) +end + +return SpinnySquare \ No newline at end of file diff --git a/src/engine/border.lua b/src/engine/border.lua new file mode 100644 index 000000000..919607b76 --- /dev/null +++ b/src/engine/border.lua @@ -0,0 +1,10 @@ +---@class Border: Class +local Border = Class() + +function Border:init() +end + +function Border:draw() +end + +return Border \ No newline at end of file diff --git a/src/engine/game/game.lua b/src/engine/game/game.lua index 047719604..940852170 100644 --- a/src/engine/game/game.lua +++ b/src/engine/game/game.lua @@ -14,7 +14,7 @@ ---@field lock_movement boolean ---@field key_repeat boolean ---@field started boolean ----@field border string +---@field border Border --- ---@field previous_state string ---@field state string @@ -128,22 +128,29 @@ function Game:leave() self.quick_save = nil end ----@return string +---@return Border function Game:getBorder() return self.border end ----@param border? string +---@param border? string|Border ---@param time? number function Game:setBorder(border, time) time = time or 1 - + local new_border_id = border + if type(border) ~= "string" then + new_border_id = border.id + end if time == 0 then Kristal.showBorder(0) - elseif time > 0 and Kristal.getBorder() ~= border then + elseif time > 0 and Kristal.getBorder().id ~= new_border_id then Kristal.transitionBorder(time) end + if type(border) == "string" then + local border_class = Registry.createBorder(border) + if border_class then border = border_class end + end self.border = border end diff --git a/src/engine/imageborder.lua b/src/engine/imageborder.lua new file mode 100644 index 000000000..6cd0102cd --- /dev/null +++ b/src/engine/imageborder.lua @@ -0,0 +1,20 @@ +---@class ImageBorder: Border +---@overload fun(texture:love.Image|string, id?: string) +local ImageBorder, super = Class(Border) + +function ImageBorder:init(texture, path) + super.init(self) + if type(texture) == "string" then + texture = Assets.getTexture("borders/"..texture) + path = texture + end + self.texture = texture + self.id = path +end + +function ImageBorder:draw() + super.draw(self) + Draw.draw(self.texture, 0, 0, 0, BORDER_SCALE) +end + +return ImageBorder \ No newline at end of file diff --git a/src/engine/registry.lua b/src/engine/registry.lua index 495cf5d1e..816702028 100644 --- a/src/engine/registry.lua +++ b/src/engine/registry.lua @@ -60,7 +60,8 @@ Registry.paths = { ["maps"] = "world/maps", ["events"] = "world/events", ["controllers"] = "world/controllers", - ["shops"] = "shops" + ["shops"] = "shops", + ["borders"] = "borders", } ---@param preload boolean? @@ -97,6 +98,7 @@ function Registry.initialize(preload) Registry.initEvents() Registry.initControllers() Registry.initShops() + Registry.initBorders() Kristal.callEvent(KRISTAL_EVENT.onRegistered) end @@ -464,6 +466,21 @@ function Registry.createShop(id, ...) end end +---@param id string +---@param ... any +---@return Border +function Registry.createBorder(id, ...) + if self.borders[id] then + return self.borders[id](...) + else + local texture = Assets.getTexture("borders/"..id) + if texture then + return ImageBorder(texture,id) + end + return Border() + end +end + -- Register Functions -- ---@param id string @@ -604,6 +621,12 @@ function Registry.registerShop(id, class) self.shops[id] = class end +---@param id string +---@param border Border +function Registry.registerBorder(id, border) + self.borders[id] = border +end + -- Internal Functions -- function Registry.initGlobals() @@ -874,6 +897,18 @@ function Registry.initShops() Kristal.callEvent(KRISTAL_EVENT.onRegisterShops) end +function Registry.initBorders() + self.borders = {} + + for _,path,border in self.iterScripts(Registry.paths["borders"]) do + assert(border ~= nil, '"borders/'..path..'.lua" does not return value') + border.id = border.id or path + self.registerBorder(border.id, border) + end + + Kristal.callEvent(KRISTAL_EVENT.onRegisterBorders) +end + ---@param base_path string ---@param exclude_folder boolean? ---@return fun() : string?, string?, ... diff --git a/src/kristal.lua b/src/kristal.lua index ec34aeb2f..e723b5c38 100644 --- a/src/kristal.lua +++ b/src/kristal.lua @@ -200,7 +200,8 @@ function love.load(args) end if border then - local border_texture = Assets.getTexture("borders/" .. border) + -- ugly hack for a ternary with falsy value in the middle + local border_texture = (isClass(border) and {} or {Assets.getTexture("borders/" ..border)})[1] love.graphics.scale(Kristal.getGameScale()) Draw.setColor(1, 1, 1, dynamic and BORDER_ALPHA or 1) @@ -213,7 +214,10 @@ function love.load(args) Draw.draw(border_texture, 0, 0, 0, BORDER_SCALE) end if dynamic then - Kristal.callEvent(KRISTAL_EVENT.onBorderDraw, border, border_texture) + if isClass(border) then + border:draw() + end + Kristal.callEvent(KRISTAL_EVENT.onBorderDraw, border.id, border_texture) end love.graphics.pop() Draw.setColor(1, 1, 1, 1) @@ -1353,7 +1357,7 @@ function Kristal.getRelativeBorderSize() return 0, 0 end ----@return string|nil border The currently displayed border, or `nil` if borders are disabled. +---@return Border|nil border The currently displayed border, or `nil` if borders are disabled. function Kristal.getBorder() if not REGISTRY_LOADED then return nil @@ -1372,12 +1376,12 @@ function Kristal.getBorder() return nil end ----@return string|nil border The currently displayed border if dynamic borders are enabled. +---@return Border|nil border The currently displayed border if dynamic borders are enabled. function Kristal.processDynamicBorder() if Kristal.getState() == Game then return Game:getBorder() elseif Kristal.getState() == MainMenu then - return "castle" + return ImageBorder("castle") end end