diff --git a/sonic-bluestreak.love/scenes/battlesystem/actors/battler.lua b/sonic-bluestreak.love/scenes/battlesystem/actors/battler.lua new file mode 100644 index 0000000..5a7506b --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/actors/battler.lua @@ -0,0 +1,140 @@ +local Parent = require("scenes.battlesystem.actors.movable") +local Battler = Parent:extend() + +local outputColor = { + good = {0, 1, 0}, + bad = {1, 0, 0}, + pp = {0.3, 0.8, 1} +} + +function Battler:new(world, x, y, z, owner) + Battler.super.new(self, world, x, y, z) + + self.isBattler = true + self.isActive = false + self.debugActiveTimer = 0 + + self.output = {} + self.output.string = "0" + self.output.isBad = true + self.output.type = "" + self.showOutput = false + self.outputY = 0 + + self.isSelected = false + self.owner = owner + + self.isDefending = false +end + +function Battler:destroy() + Battler.super.destroy(self) +end + +function Battler:getOutputY() + return self.sprHeight or 32 +end + +function Battler:avoidedAttack() + self:newOutput("", "MISS") +end + +function Battler:setDamageNumber(number, isPP) + local type = "good" + if (isPP == true) then type = "pp" end + if (number < 0) then type = "bad" end + local string = math.abs(math.floor(number)) + + self:newOutput(type, string) +end + +function Battler:newOutput(type, string) + self.output.type = type or "" + self.output.string = string or "error" + self.outputY = self:getOutputY() - 8 + self.showOutput = true + + self.tweens:newTween(0, 0.4, {outputY = self:getOutputY()}, "outQuad") + self.tweens:newTimer(0.5, "removeOutput") +end + +function Battler:getOuputColor(type) + return outputColor[type] or {1,1,1} +end + +function Battler:setActive() + core.debug:print("cbs/actor","actor " .. self.id .. " is active") + self.isActive = true + self.debugActiveTimer = 0 +end + +function Battler:update(dt) + Battler.super.update(self, dt) + if (self.isActive) then + self.debugActiveTimer = self.debugActiveTimer + dt + if self.debugActiveTimer >= 0.5 then + core.debug:print("cbs/battler", "counter ended, switching active battler") + self.isActive = false + self.world:switchActiveBattler() + end + end +end + +-- Movement +-- Some specific movement function + +function Battler:land() + self:changeAnimation("idle") +end + +-- CHOREGRAPHY FUNCTIONS +-- All functions related to the choregraphy system + +function Battler:choregraphyEnded() + self:resetMovement() +end + +-- DAMAGE FUNCTIONS + +function Battler:getHurt() + +end + +function Battler:die() + self:destroy() +end + +-- DRAW FUNCTIONS +function Battler:drawOutput() + if (self.showOutput) then + local x, y = self.world.map:gridToPixel(self.x, self.y, true) + local color = self:getOuputColor(self.output.type) + love.graphics.setColor(color[1], color[2], color[3], 1) + + self.assets.fonts["hudnbrs_small"]:print(self.output.string, x, y - self.outputY - self.z, "center") + utils.graphics.resetColor() + end +end + +function Battler:draw() + local x, y = self.world.map:gridToPixel(self.x, self.y, true) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle("fill", x - 8, y - 32, 16, 32) + love.graphics.setColor(1, 1, 1, 1) +end + +function Battler:initSprite() + if (self.assets.sprites[self.owner.name] == nil) then + self.assets:addSprite(self.owner.name, self:getSpritePath()) + end + self.assets.sprites[self.owner.name]:setCustomSpeed(16) + self:setSprite(self.owner.name, 32, 48, true) + self:cloneSprite() + self:changeAnimation("idle") +end + +function Battler:validateAction() + +end + +return Battler diff --git a/sonic-bluestreak.love/scenes/battlesystem/actors/ennemy.lua b/sonic-bluestreak.love/scenes/battlesystem/actors/ennemy.lua new file mode 100644 index 0000000..fcc0b96 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/actors/ennemy.lua @@ -0,0 +1,55 @@ +local Battler = require("scenes.battlesystem.actors.battler") +local Ennemy = Battler:extend() + +function Ennemy:new(world, x, y, owner) + Ennemy.super.new(self, world, x, y, 0, owner) + self.isEnnemy = true + + self.actionPerTurn = 2 + self:initSprite() + if (self.owner:haveProtecType("aerial")) then + self.z = 10 + self.start.z = 10 + end + self.sprHeight = self.owner.abstract.data.hudHeight + 14 +end + +function Ennemy:setCheapEffect(cheapEffect) + if (cheapEffect) then + self.sprite.sx = 2 + self.sprite.sy = 2 + end +end + +function Ennemy:draw() + self:drawSprite(0, -self.z) + local x, y = self.world.map:gridToPixel(self.x, self.y, true) + + self.owner:drawOversprite(x - 12, y - ((self.sprHeight - 8) * self.sprite.sy) - self.z) + + if (self.isSelected) then + self.assets.images["cursorpeak"]:draw(x - 7, (y - 24 - self.sprHeight) - self.z) + end + + self:drawOutput() +end + +function Ennemy:die() + self.assets.sfx["badnicsBoom"]:play() + self.world.obj.GFX(self.world, self.x, self.y, self.z, "boom1", self, false) + self:destroy() +end + +function Ennemy:getStats() + return self.data.stats +end + +-- ASSETS FUNCTIONS +-- Load and play assets needed by the character + +function Ennemy:getSpritePath() + return "datas/gamedata/ennemies/" .. self.owner.category .. "/" .. self.owner.name .. "/sprites" +end + + +return Ennemy diff --git a/sonic-bluestreak.love/scenes/battlesystem/actors/gfx.lua b/sonic-bluestreak.love/scenes/battlesystem/actors/gfx.lua new file mode 100644 index 0000000..8e1be50 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/actors/gfx.lua @@ -0,0 +1,73 @@ +local Parent = require("scenes.battlesystem.actors.movable") +local GFX = Parent:extend() +local GFX_DIRECTORY = "assets/sprites/gfx/" + +function GFX:new(world, x, y, z, spritename, creator, blockProcess, tag) + GFX.super.new(self, world, x, y, z) + + if (creator.choregraphy ~= nil) then + self.char = self:getCharacter(creator.choregraphy.fighter) + end + self:setAnimation(spritename) + + self.creator = creator + self.blockProcess = blockProcess or false + self.tag = tag or "" + + if (not utils.string.isEmpty(self.tag)) then + self:setIndexName(self.tag) + end + + self.direction = 1 +end + +function GFX:getCharacter(fighter) + if (fighter.isHero) then + return fighter.abstract.simplename + end + return nil +end + +function GFX:setAnimation(spritename) + local defaultPath = GFX_DIRECTORY .. spritename + if (utils.string.isEmpty(self.char)) then + self:loadAnimation(spritename, defaultPath) + else + local charGFXPath = "datas/gamedata/characters/" .. self.char .. "/gfx/" .. spritename + if (utils.filesystem.exists(charGFXPath .. ".lua")) then + self:loadAnimation(self.char .. spritename, charGFXPath) + else + self:loadAnimation(spritename, defaultPath) + end + end +end + +function GFX:loadAnimation(spritename, path) + if self.world.assets.sprites[spritename] == nil then + self.world.assets:addSprite(spritename, path) + end + local width, height = self.world.assets.sprites[spritename]:getDimensions() + self:setSprite(spritename, width/2, height, true) + self:cloneSprite() +end + +function GFX:animationEnded(animation) + core.debug:print("gfx", 'Current animation "' .. animation .. '" have ended, destroying gfx') + if (self.blockProcess) and (self.creator ~= nil) and (self.creator.getSignal ~= nil) then + self.creator:getSignal("gfxEnded") + end + if ((self.creator ~= nil) and (self.creator.choregraphy ~= nil) and (not utils.string.isEmpty(self.tag))) then + self.creator.choregraphy:finishTagAction(self.tag) + end + self:destroy() +end + +function GFX:draw() + self:drawSprite(0, -self.z) +end + +function GFX:drawShadow() + +end + +return GFX diff --git a/sonic-bluestreak.love/scenes/battlesystem/actors/hero.lua b/sonic-bluestreak.love/scenes/battlesystem/actors/hero.lua new file mode 100644 index 0000000..e274a78 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/actors/hero.lua @@ -0,0 +1,94 @@ +local Battler = require("scenes.battlesystem.actors.battler") +local Hero = Battler:extend() + +-- INIT FUNCTIONS +-- Initialize the hero + +function Hero:new(world, x, y, owner, charnumber) + Hero.super.new(self, world, x, y, 0, owner) + self:initSprite() + self.isKo = false + self.sprHeight = 32 +end + +-- UPDATE FUNCTION +-- Update the hero + +function Hero:update(dt) + Hero.super.update(self, dt) + self:updateAnimation(dt) +end + +-- HURT/DEATH FUNCTIONS + +function Hero:getHurt() + self:changeAnimation("hurt") +end + +function Hero:die() + if (not self.isKo) then + self:changeAnimation("getKo") + self.isKo = true + end +end + +function Hero:revive() + if (self.isKo) then + self:changeAnimation("idle") + self.isKo = false + self.isDefending = false + end +end + +function Hero:setAsKo() + self:changeAnimation("ko") + self.isKo = true +end + +-- ASSETS FUNCTIONS +-- Load and play assets needed by the character + +function Hero:getSpritePath() + return "datas/gamedata/characters/" .. self.owner.name .. "/sprites" +end + +function Hero:updateAnimation(dt) + if (self.z > 0 and self.jump.useDefaultAnimation) then + if self.zspeed > 0 then + self:changeAnimation("jump") + else + self:changeAnimation("fall") + end + end + + self:setCustomSpeed(self.speed * 160 * dt) +end + +function Hero:getNewAnimation(animation) + if (animation == "hurt") then + self:changeAnimation("idle") + end +end + +function Hero:flee() + if (not self.isKo) then + self:changeAnimation("walk") + self:goTo(-80, self.y, 3) + end +end + +-- DRAW FUNCTIONS +-- Draw everything related to the hero + +function Hero:draw() + self:drawSprite(0, -self.z) + + if (self.isSelected) then + local x, y = self.world.map:gridToPixel(self.x, self.y, true) + self.assets.images["cursorpeak"]:draw(x - 7, y - 24 - 32) + end + + self:drawOutput() +end + +return Hero diff --git a/sonic-bluestreak.love/scenes/battlesystem/actors/init.lua b/sonic-bluestreak.love/scenes/battlesystem/actors/init.lua new file mode 100644 index 0000000..262dafe --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/actors/init.lua @@ -0,0 +1,10 @@ +local entities = {} + +local baseURI = "scenes.battlesystem.actors." + +entities.Hero = require(baseURI .. "hero") +entities.Ennemy = require(baseURI .. "ennemy") +entities.Battler = require(baseURI .. "battler") +entities.GFX = require(baseURI .. "gfx") + +return entities diff --git a/sonic-bluestreak.love/scenes/battlesystem/actors/movable.lua b/sonic-bluestreak.love/scenes/battlesystem/actors/movable.lua new file mode 100644 index 0000000..d9593e0 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/actors/movable.lua @@ -0,0 +1,267 @@ +local ParentObject = require "scenes.battlesystem.actors.parent" +local Movable = ParentObject:extend() + +local MOVEMENT_NONE = "none" +local MOVEMENT_MOTION = "motion" +local MOVEMENT_TARGET = "target" + +local ZGRAVITY = 12 + +local MIDDLE_ARENA = 6 + +function Movable:new(world, x, y, z) + Movable.super.new(self, world, x, y, z) + self.direction = utils.math.sign(MIDDLE_ARENA - x) + + self.start = {} + self.start.x = x + self.start.y = y + self.start.z = z + self.start.direction = self.direction + + self:resetMovement() +end + +-- MOVE FUNCTIONS +-- All functions handling the moving + +function Movable:resetMovement() + self:resetMotion() + self:resetJump() + self:resetDirection() + self:resetTarget() +end + +function Movable:resetMovementType() + self.movementType = MOVEMENT_NONE +end + +function Movable:stopMoving() + self:resetMotion() + self:finishAction("goTo") +end + +function Movable:update(dt) + Movable.super.update(self, dt) + self:updateMotion(dt) + self:updateDirection() + self:updatePreviousPosition() +end + +function Movable:updatePreviousPosition() + self.xprevious = self.x + self.yprevious = self.y + self.zprevious = self.z +end + +-- GoTo movement functions + +function Movable:goTo(dx, dy, duration) + self:resetMotion() + self:setTarget(dx, dy) + local speed = utils.math.pointDistance(self.x, self.y, dx, dy) / duration + self:setMotionToPoint(speed, dx, dy) + + self.movementType = MOVEMENT_TARGET +end + +function Movable:goTo3D(dx, dy, dz, duration) + self:resetMotion() + self:resetJump() + self:setTarget(dx, dy, dz) + local speed = utils.math.pointDistance3D(self.x, self.y, self.z, dx, dy, dz) / duration + self:setMotionToPoint(speed, dx, dy, dz) + + self.movementType = MOVEMENT_TARGET +end + +-- MOTION HANDLING + +function Movable:resetMotion() + self.speed, self.angle = 0, 0 + self.xspeed, self.yspeed = 0,0 + + self:updatePreviousPosition() + self:resetMovementType() +end + +function Movable:setMotion(speed, angle, vertAngle) + self.speed = speed + self.angle = angle + self.motion3D = (vertAngle ~= nil) + if (self.motion3D) then + self.vertAngle = vertAngle + end + self.movementType = MOVEMENT_MOTION +end + +function Movable:setMotionToPoint(speed, dx, dy, dz) + local angle = utils.math.pointDirection(self.x, self.y, dx, dy) + local vertAngle = nil + if (dz ~= nil) then + local distance2D = utils.math.pointDistance(self.x, self.y, dx, dy) + vertAngle = utils.math.pointDirection(0, self.z, distance2D, dz) + end + self:setMotion(speed, angle, vertAngle) +end + +function Movable:updateMotion(dt) + self:checkTarget(dt) + self.xspeed, self.yspeed, self.zspeed = self:getMotionCoord() + self.x = self.x + (self.xspeed) * dt + self.y = self.y + (self.yspeed) * dt + self.z = self.z + (self.zspeed) * dt + + self:checkGround() +end + +function Movable:getMotionCoord() + local gspeed, xspeed, yspeed, zspeed + if (self.motion3D) then + gspeed, zspeed = utils.math.lengthdir(self.speed, self.vertAngle) + xspeed, yspeed = utils.math.lengthdir(gspeed, self.angle) + else + xspeed, yspeed = utils.math.lengthdir(self.speed, self.angle) + zspeed = self:getJumpMotion() + end + + return xspeed, yspeed, zspeed +end + +-- Target handling + +function Movable:setTarget(x, y, z) + self.target = {} + self.target.x = x + self.target.y = y + self.target.z = z +end + +function Movable:isTargetActive() + return (self.target ~= nil) +end + +function Movable:resetTarget() + self.target = nil +end + +function Movable:isNearTarget(distance) + if (not self:isTargetActive()) then + return false + end + + if (self.target.z == nil) then + return (utils.math.pointDistance(self.x, self.y, self.target.x, self.target.y) <= distance) + else + return (utils.math.pointDistance3D(self.x, self.y, self.z, self.target.x, self.target.y, self.target.z) <= distance) + end +end + +function Movable:checkTarget(dt) + if (self:isTargetActive()) then + local isNearTarget = self:isNearTarget(self.speed * dt) + if (isNearTarget) then + self:finishTarget() + end + end +end + +function Movable:finishTarget() + -- TODO: add a one-time signal to target handling + if (self.movementType == MOVEMENT_TARGET) then + self.x = self.target.x + self.y = self.target.y + if (self.target.z ~= nil) then + self.z = self.target.z + end + self:stopMoving() + end + self:resetTarget() +end + +-- Direction handling + +function Movable:resetDirection() + self.direction = self.start.direction + self.directionPrevious = self.start.direction + self.directionLocked = false +end + +function Movable:updateDirection() + -- Handle direction + if math.abs(self.xspeed) >= 0.01 then + if not (self.directionLocked or self.jump.lockDir) then + self.direction = utils.math.sign(self.xspeed) + end + end +end + +-- Jump system + +function Movable:resetJump() + self.jump = {} + self.jump.useDefaultAnimation = true + self.jump.isJumping = false + self.jump.bounceNumber = 0 + self.jump.stopWhenLanding = false + self.jump.lockDir = false + + self.zspeed = 0 + self.motion3D = false + self.vertAngle = 0 +end + +function Movable:stopJumping() + self.z = 0 + self.tweens:newTimer(0.01, "jump") + if (self.jump.stopWhenLanding) then + self:resetMotion() + end + self:resetJump() + self:land() +end + +function Movable:land() + -- Empty function +end + +function Movable:setJump(power, bounceNumber, useDefaultAnimation) + self.zspeed = (power * 60) + self.jump.useDefaultAnimation = useDefaultAnimation + self.jump.bounceNumber = bounceNumber + self.jump.isJumping = true +end + +function Movable:jumpTo(dx, dy, height, speed, useDefaultAnimation) + height = height or 4 + self:setMotionToPoint(speed, dx, dy) + + self:setJump(height, 0, useDefaultAnimation) + self.jump.stopWhenLanding = true +end + +function Movable:jumpBack(height, speed) + self:jumpTo(self.start.x, self.start.y, height, speed, true) + self.jump.lockDir = true +end + +function Movable:getJumpMotion() + if (self.jump.isJumping) then + return self.zspeed - ZGRAVITY + else + return 0 + end +end + +function Movable:checkGround() + if (self.z <= 0 and self.jump.isJumping) then + if (self.jump.bounceNumber > 0) then + self.zspeed = self.zspeed * -0.5 + self.jump.bounceNumber = self.jump.bounceNumber - 1 + else + self:stopJumping() + end + end +end + +return Movable \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/actors/parent.lua b/sonic-bluestreak.love/scenes/battlesystem/actors/parent.lua new file mode 100644 index 0000000..d1d5d63 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/actors/parent.lua @@ -0,0 +1,296 @@ +local Parent = Object:extend() -- On créer la classe des entitées, c'est la classe de base + +local maputils = require "scenes.battlesystem.utils" + +local TweenManager = require "birb.classes.time" + +-- INIT FUNCTION +-- Initilize the actor + +function Parent:new(world, x, y, z) + self.depth = 0 + self.x = x + self.y = y + self.z = z or 0 + self.direction = 1 + --self.id = self.world.creationID + + self.world = world + self.assets = self.world.assets + self.scene = self.world.scene + self.map = self.world.map + + self.maputils = maputils + + self.isHero = false + self.isActor = false + self.isEnnemy = false + self.isDestroyed = false + + self.tweens = TweenManager(self) + + self:resetTags() + + self:setSprite() + self:register() +end + +function Parent:setIndexName(indexName) + self.indexName = indexName + self.world.index[self.indexName] = self +end + +function Parent:register() + self.world:registerActor(self) +end + +function Parent:destroy() + self.world:destroyActor(self) + self.isDestroyed = true + if (self.indexName ~= nil) then + self.world.index[self.indexName] = nil + end +end + +function Parent:update(dt) + self:updateSprite(dt) + self.tweens:update(dt) +end + +-- GET FUNCTIONS +-- Get informations + +function Parent:getCoordinate() + return self.x, self.y, self.z +end + +-- SPRITE FUNCTIONS +-- Handle the character sprite + +function Parent:setSprite(spritename, ox, oy, active) + self.sprite = {} + self.sprite.name = spritename or nil + self.sprite.ox = ox or 0 + self.sprite.oy = oy or 0 + self.sprite.sx = 1 + self.sprite.sy = 1 + self.sprite.exist = (spritename ~= nil) + self.sprite.clone = nil + self.sprite.active = active or false + + self:resetFrameSignal() +end + +function Parent:cloneSprite() + if self.sprite.name ~= nil then + self.sprite.clone = self.assets.sprites[self.sprite.name]:clone() + self.sprite.clone:setCallback(self) + end +end + +function Parent:changeAnimation(animation, restart) + self:resetFrameSignal() + if (self.sprite.clone == nil) then + self.assets.sprites[self.sprite.name]:changeAnimation(animation, restart) + else + self.sprite.clone:changeAnimation(animation, restart) + end +end + +function Parent:setAnimSpeed(speed) + if (self.sprite.clone == nil) then + self.assets.sprites[self.sprite.name]:setSpeedFactor(speed) + else + self.sprite.clone:setSpeedFactor(speed) + end +end + +function Parent:animationEnded(animation) + if (self.currentlyBlocking ~= nil and self.blockedBy=="animation") then + self:unblockChoregraphy() + end + self:unlockTag("animation") + self:getNewAnimation(animation) +end + +function Parent:getNewAnimation(animation) + +end + +function Parent:setCustomSpeed(customSpeed) + if (self.sprite.clone == nil) then + self.assets.sprites[self.sprite.name]:setCustomSpeed(customSpeed) + else + self.sprite.clone:setCustomSpeed(customSpeed) + end +end + +function Parent:updateSprite(dt) + if (self.sprite.clone ~= nil) then + self.sprite.clone:update(dt) + end +end + +function Parent:setSpriteScallingX(sx) + local sx = sx or 1 + + self.sprite.sx = sx +end + +function Parent:setSpriteScallingY(sy) + local sy = sy or 1 + + self.sprite.sy = sy +end + +function Parent:getCurrentAnimation() + if (self.sprite.clone == nil) then + return self.assets.sprites[self.sprite.name]:getCurrentAnimation() + else + return self.sprite.clone:getCurrentAnimation() + end +end + + +function Parent:getSpriteScalling() + return self.sprite.sx, self.sprite.sy +end + +function Parent:getFrame() + if (self.sprite.name ~= nil) then + if (self.sprite.clone ~= nil) then + return self.sprite.clone:getFrame() + else + return self.assets.sprites[self.sprite.name]:getFrame() + end + end +end + +function Parent:getRelativeFrame() + if (self.sprite.name ~= nil) then + if (self.sprite.clone ~= nil) then + return self.sprite.clone:getRelativeFrame() + else + return self.assets.sprites[self.sprite.name]:getRelativeFrame() + end + end +end + +function Parent:getAnimationDuration() + if (self.sprite.name ~= nil) then + if (self.sprite.clone ~= nil) then + return self.sprite.clone:getAnimationDuration() + else + return self.assets.sprites[self.sprite.name]:getAnimationDuration() + end + end +end + +function Parent:drawSprite(tx, ty) + utils.graphics.resetColor() + + local x, y = self.world.map:gridToPixel(self.x, self.y, true) + + local tx = tx or 0 + local ty = ty or 0 + + if (self.sprite.active) then + local sx = self.direction * self.sprite.sx + local sy = self.sprite.sy + if (self.sprite.clone ~= nil) then + self.sprite.clone:draw(x + tx, y + ty, 0, sx, sy, self.sprite.ox, self.sprite.oy) + else + self.assets.sprites[self.sprite.name]:draw(x + tx, y + ty, 0, sx, sy, self.sprite.ox, self.sprite.oy) + end + end +end + +-- FRAME SIGNAL +-- Get signals from specific frames of the animation + +function Parent:resetFrameSignal() + self.frameSignals = {} +end + +function Parent:receiveFrameSignal(signal) + table.insert(self.frameSignals, signal) +end + +function Parent:haveFrameSignal(signal) + return utils.table.contain(self.frameSignals, signal) +end + +-- TAGS +-- Handle tags + +function Parent:resetTags() + self.tags = {} + self.choregraphy = nil +end + +function Parent:addTaggedAction(tag, choregraphy, taggedBy) + if (not utils.string.isEmpty(tag)) then + self.tags[tag] = taggedBy + self.choregraphy = choregraphy + end +end + +function Parent:unlockTag(taggedBy) + for tag, actionTag in pairs(self.tags) do + if (self.choregraphy ~= nil) and (actionTag == taggedBy) then + self.choregraphy:finishTagAction(tag) + self.tags[tag] = nil + end + end +end + +-- CHOREGRAPHY BLOCKING +-- Handle blocking/unblocking the choregraphy + +function Parent:blockChoregraphy(isBlocking, currentlyBlocking, blockedBy) + if (isBlocking) then + self.currentlyBlocking = currentlyBlocking + self.blockedBy = blockedBy + end +end + +function Parent:unblockChoregraphy() + self.currentlyBlocking:finish() + self.currentlyBlocking = nil +end + +function Parent:timerResponse(signal) + self:finishAction(signal) + + if (signal == "removeOutput") then + self.showOutput = false + end +end + +function Parent:finishAction(signal) + if ((self.currentlyBlocking ~= nil) and (signal == self.blockedBy)) then + self:unblockChoregraphy() + end + self:unlockTag(signal) +end + +-- DRAW FUNCTIONS +-- Handle draw functions + +function Parent:draw() + +end + +function Parent:drawShadow() + local x, y = self.world.map:gridToPixel(self.x, self.y, true) + self.assets.images["actorsShadow"]:draw(x, y, 0, self.sprite.sx, self.sprite.sy, 12, 5) + if (self.isSelected == true) then + self.assets.sprites["cursorground"]:draw(x - 2, y - 1, 0, 1, 1, 12, 5) + end +end + +function Parent:drawHUD() + +end + +return Parent diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/conditions.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/conditions.lua new file mode 100644 index 0000000..b62c1cd --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/conditions.lua @@ -0,0 +1,43 @@ +local Conditions = {} + +function Conditions.sentDamage(cond, predicate, asker) + return asker.haveSentDamage +end + +function Conditions.qteSuccess(cond, predicate, asker) + return asker:isQteSuccess(tonumber(cond[2])) +end + +function Conditions.qteFailure(cond, predicate, asker) + return (Conditions.qteSuccess(cond, predicate, asker) == false) +end + +function Conditions.none(cond, predicate, asker) + return true +end + +function Conditions.actionFinished(cond, predicate, asker) + return asker:testTagAction(cond[2], 2) +end + +function Conditions.actionStarted(cond, predicate, asker) + return asker:testTagAction(cond[2], 1) +end + +function Conditions.counter(cond, predicate, asker) + return predicate.utils.testVariables(asker:getCounter(cond[2]), cond[3], cond[4]) +end + +function Conditions.haveFrameSignal(cond, predicate, asker) + return asker:haveFrameSignal(cond[2]) +end + +function Conditions.hasNextTarget(cond, predicate, asker) + return asker:hasNextTarget() +end + +function Conditions.hasSubChoregraphiesActive(cond, predicate, asker) + return asker:hasSubChoregraphiesActive() +end + +return Conditions \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/init.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/init.lua new file mode 100644 index 0000000..3bb90c9 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/init.lua @@ -0,0 +1,51 @@ +local ChoregraphySystem = Object:extend() + +local QteMixin = require "scenes.battlesystem.choregraphy.mixins.qtes" +local StepsMixin = require "scenes.battlesystem.choregraphy.mixins.steps" +local TagsMixin = require "scenes.battlesystem.choregraphy.mixins.tags" +local CountersMixin = require "scenes.battlesystem.choregraphy.mixins.counters" +local WrappersMixin = require "scenes.battlesystem.choregraphy.mixins.wrappers" +local SubChoregraphiesMixin = require "scenes.battlesystem.choregraphy.mixins.subchoregraphies" + +local TweenManager = require "birb.classes.time" + +ChoregraphySystem:implement(QteMixin) +ChoregraphySystem:implement(StepsMixin) +ChoregraphySystem:implement(TagsMixin) +ChoregraphySystem:implement(CountersMixin) +ChoregraphySystem:implement(WrappersMixin) +ChoregraphySystem:implement(SubChoregraphiesMixin) + +function ChoregraphySystem:new(action, choregraphy, subChoregraphy) + self:initWrappers(action) + + self:initSteps(choregraphy) + self:initQte() + self:initTagActions() + self:initCounters() + self:initSubchoregraphies(subChoregraphy) + + self.tweens = TweenManager(self) + + self.actor:resetFrameSignal() +end + +function ChoregraphySystem:update(dt) + self:updateSteps(dt) + self.tweens:update(dt) + self:updateSubChoregraphies(dt) +end + +function ChoregraphySystem:timerResponse(signal) + if (signal == "startNextTarget") then + self:startNextTarget() + end +end + +function ChoregraphySystem:endChoregraphy() + self.actor:choregraphyEnded() + self.action:choregraphyEnded() + self.fighter.turnSystem:applyDeath() +end + +return ChoregraphySystem diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/counters.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/counters.lua new file mode 100644 index 0000000..551c9f4 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/counters.lua @@ -0,0 +1,18 @@ +local CountersMixin = Object:extend() + +function CountersMixin:initCounters() + self.counters = {} +end + +function CountersMixin:getCounter(counterName) + return (self.counters[counterName] or 0) +end + +function CountersMixin:setCounter(counterName, number, relative) + if (relative == true) then + number = number + self:getCounter(counterName) + end + self.counters[counterName] = number +end + +return CountersMixin diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/qtes.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/qtes.lua new file mode 100644 index 0000000..2953ed6 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/qtes.lua @@ -0,0 +1,54 @@ +local QteMixin = Object:extend() + +local qteObjectList = require "scenes.battlesystem.choregraphy.qte" + +function QteMixin:initQte() + self.qte = {} + self.qte.current = nil + self.qte.wasSuccess = false + self.qte.isActive = false + self.qte.list = {} +end + +function QteMixin:updateQte(dt) + if (self.qte.current ~= nil) then + self.qte.current:updateQte(dt, self.qte.isActive) + end +end + +function QteMixin:isQteSuccess(qteID) + qteID = qteID or #self.qte.list + return self.qte.list[qteID] +end + +function QteMixin:addQTE(action, origin, qteBaseData, blockProcess, tag) + local qteData = core.datas:parse("qtesteps", qteBaseData) + if (qteObjectList[qteData.name] ~= nil) then + core.debug:print("cbs/choregraphy", "Starting qte " .. qteData.name) + self.qte.current = qteObjectList[qteData.name](self, qteData.arguments, 0, 0) + self.qte.current:blockAction(action, blockProcess) + self.qte.current:setOrigin(origin) + self.qte.current:setTag(tag) + self.qte.isActive = true + end +end + +function QteMixin:endQte(success) + self.qte.isActive = false + self.qte.wasSuccess = success + + table.insert(self.qte.list, success) + self.rewards:addQTE(success) +end + +function QteMixin:removeQte() + self.qte.current = nil +end + +function QteMixin:drawQte() + if (self.qte.current ~= nil) then + self.qte.current:draw() + end +end + +return QteMixin diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/steps.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/steps.lua new file mode 100644 index 0000000..a21bc28 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/steps.lua @@ -0,0 +1,74 @@ +local StepsMixins = Object:extend() + +local Predicate = require "birb.classes.predicate" +local Conditions = require "scenes.battlesystem.choregraphy.conditions" + +local stepObjectList = require "scenes.battlesystem.choregraphy.step" + +function StepsMixins:initSteps(choregraphy) + self.currentStepId = 0 + self.currentStep = nil + self.stepList = choregraphy +end + +function StepsMixins:haveNextStep() + return ((self.currentStepId + 1) <= #self.stepList) +end + +-- UPDATE + +function StepsMixins:updateSteps(dt) + if (self.currentStep ~= nil) then + self.currentStep:updateStep(dt) + else + self:switchStep() + end +end + +function StepsMixins:checkCondition(condition) + local predicate = Predicate.createPredicate(condition, Conditions, self) + return predicate:solve() +end + +function StepsMixins:parseStep(step) + local tagName = "" + if (step[1] == "taggedAction") then + tagName = step[2] + step = step[3] + end + local stepData = core.datas:parse("choregraphystep", step) + core.debug:print("cbs/choregraphy", "Starting step " .. stepData.name) + return stepData, tagName +end + +function StepsMixins:switchStep() + if self:haveNextStep() then + self.currentStepId = self.currentStepId + 1 + local stepData, tagName = self:parseStep(self.stepList[self.currentStepId]) + if (stepObjectList[stepData.name] ~= nil and self:checkCondition(stepData.condition)) then + self.currentStep = stepObjectList[stepData.name](self, stepData.arguments) + self.currentStep:addTag(tagName) + end + else + self:endChoregraphy() + end +end + +-- SKIP OR END STEPS + +function StepsMixins:skipToStepByTag(tag) + self:skipToStep(self:findTaggedAction(tag)) +end + +function StepsMixins:skipToStep(id) + if (self.stepList[id] ~= nil) then + self.currentStepId = id - 1 + self:switchStep() + end +end + +function StepsMixins:endStep() + self.currentStep = nil +end + +return StepsMixins diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/subchoregraphies.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/subchoregraphies.lua new file mode 100644 index 0000000..fcda1d3 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/subchoregraphies.lua @@ -0,0 +1,73 @@ +local SubChoregraphiesMixin = Object:extend() + +local SubChoregraphy = require "scenes.battlesystem.choregraphy.subchoregraphy" + +function SubChoregraphiesMixin:initSubchoregraphies(subChoregraphy) + self.subChoregraphies = {} + self.subChoregraphies.isActive = (self.target == nil) + self.subChoregraphies.steps = subChoregraphy + self.subChoregraphies.currentTarget = 0 + self.subChoregraphies.waitTime = 0 + self.subChoregraphies.list = {} +end + +function SubChoregraphiesMixin:startSubChoregraphies(waitTime) + self.subChoregraphies.currentTarget = 0 + self.subChoregraphies.waitTime = waitTime + self:startNextTarget() +end + +function SubChoregraphiesMixin:updateSubChoregraphies(dt) + for _, subchoregraphy in ipairs(self.subChoregraphies.list) do + subchoregraphy:update(dt) + end +end + +function SubChoregraphiesMixin:startNextTarget() + local target = self:getNextTarget() + if (target ~= nil) then + SubChoregraphy(self, target, self.subChoregraphies.steps) + self.tweens:newTimer(self.subChoregraphies.waitTime, "startNextTarget") + end +end + +function SubChoregraphiesMixin:registerSubChoregraphy(subChoregraphy) + table.insert(self.subChoregraphies.list, subChoregraphy) + self:updateSubChoregraphyIds() +end + +function SubChoregraphiesMixin:removeSubChoregraphy(subChoregraphy) + self:updateSubChoregraphyIds() + table.remove(self.subChoregraphies.list, subChoregraphy.id) + self:updateSubChoregraphyIds() +end + +function SubChoregraphiesMixin:updateSubChoregraphyIds() + for id, subchoregraphy in ipairs(self.subChoregraphies.list) do + subchoregraphy.id = id + end +end + +function SubChoregraphiesMixin:getNextTarget() + if (self:hasNextTarget()) then + self.subChoregraphies.currentTarget = self.subChoregraphies.currentTarget + 1 + return self.targetList[self.subChoregraphies.currentTarget] + end +end + +function SubChoregraphiesMixin:hasNextTarget() + return (self.targetList[self.subChoregraphies.currentTarget + 1] ~= nil) +end + +function SubChoregraphiesMixin:hasSubChoregraphiesActive() + return (#self.subChoregraphies.list > 0) +end + +function SubChoregraphiesMixin:drawSubChoregraphies() + for _, subchoregraphy in ipairs(self.subChoregraphies.list) do + subchoregraphy:draw() + end +end + + +return SubChoregraphiesMixin \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/tags.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/tags.lua new file mode 100644 index 0000000..6a58ccf --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/tags.lua @@ -0,0 +1,33 @@ +local TagsMixin = Object:extend() + +local ACTION_STARTED = 1 +local ACTION_FINISHED = 2 + +function TagsMixin:initTagActions() + self.finishedTagActions = {} +end + +function TagsMixin:findTaggedAction(tag) + for stepId, step in ipairs(self.stepList) do + if (step[1] == "taggedAction") and (step[2] == tag) then + return stepId + end + end + return 0 +end + +function TagsMixin:testTagAction(tag, statut) + local tagStatut = self.finishedTagActions[tag] or 0 + return (statut <= tagStatut) +end + +function TagsMixin:startTagAction(tag) + self.finishedTagActions[tag] = ACTION_STARTED +end + +function TagsMixin:finishTagAction(tag) + core.debug:print("choregraphy/step", "Tag action " .. tag .. " finished.") + self.finishedTagActions[tag] = ACTION_FINISHED +end + +return TagsMixin diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/wrappers.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/wrappers.lua new file mode 100644 index 0000000..c4bd086 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/mixins/wrappers.lua @@ -0,0 +1,70 @@ +local InfosMixin = Object:extend() + +function InfosMixin:initWrappers(action, target) + self.action = action + self.fighter = action.fighter + self.actor = self.fighter.actor + self.assets = self.fighter.actor.assets + self.world = self.actor.world + self.scene = self.world.scene + self.turns = self.scene.turns + self.rewards = self.turns.rewards + + self:initTargets(target or action.target) +end + +function InfosMixin:initTargets(target) + self.target = target + self.haveSentDamage = false + + if (self.target == nil) then + local _, targetEnnemies = self.action:needTarget() + self.targetList = self.fighter:getTargets(targetEnnemies == false) + end +end + +function InfosMixin:getActor(name) + if (name == "actor") then + return self.actor + elseif (name == "target") then + return self:getTargetActor() + else + return self.fighter.world:getActorByName(name) + end +end + +function InfosMixin:getTargetActor() + return self.target.actor +end + +function InfosMixin:sendDamage(power, type, element, isSpecial) + if (self.fighter.isAlive) then + if (self.target ~= nil) then + self.haveSentDamage = self.fighter:sendDamage(self.target, power, type, element, isSpecial) + else + self.haveSentDamage = self.fighter:sendDamageToAll(self.targetList, power, type, element, isSpecial) + end + else + self.haveSentDamage = false + end +end + +function InfosMixin:sendStatus(status, duration, force) + if (self.fighter.isAlive) then + if (self.target ~= nil) then + self.fighter:sendStatus(self.target, status, duration, force) + else + self.fighter:sendStatus(self.targetList, status, duration, force) + end + end +end + +function InfosMixin:haveFrameSignal(signal) + return self.actor:haveFrameSignal(signal) +end + +function InfosMixin:useItemEffect() + self.action:useItemEffect() +end + +return InfosMixin diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/init.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/init.lua new file mode 100644 index 0000000..8fe75e9 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/init.lua @@ -0,0 +1,7 @@ +local qtes = {} + +local baseURI = "scenes.battlesystem.choregraphy.qte." + +qtes["simplePrompt"] = require (baseURI .. "simpleprompt") + +return qtes diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/parent.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/parent.lua new file mode 100644 index 0000000..e14de48 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/parent.lua @@ -0,0 +1,169 @@ +local GuiElements = require "birb.modules.gui.elements.parent" +local QteParent = GuiElements:extend() + +local Prompts = require "scenes.battlesystem.choregraphy.qte.prompts" + +function QteParent:new(choregraphySystem, arguments) + self.choregraphy = choregraphySystem + self.arguments = arguments + self.isBlocking = nil + self.prompts = Prompts(self) + self.timer = 0 + self.timerActive = false + self.isSuccess = false + self.tag = "" + + QteParent.super.new(self, "qte", -1, -1, 1, 1) + + self:start() + self.isStarted = true + self:getFocus() +end + +function QteParent:setTag(tag) + self.tag = tag +end + +function QteParent:blockAction(action, isBlocked) + if (isBlocked) then + self.isBlocking = action + end +end + +function QteParent:endQte() + self.choregraphy:endQte(self.isSuccess) + if (self.isBlocking ~= nil) then + self.isBlocking:getSignal("qteEnded") + end + if (not utils.string.isEmpty(self.tag)) then + self.choregraphy:finishTagAction(self.tag) + end +end + +function QteParent:setOrigin(origin) + local x, y, z = 424/2, 240/2, 0 + local argy = 16 + local battleCoord = false + if (origin == "target") then + local target = self.choregraphy.action.target + x, y = target.actor:getCoordinate() + z = target.actor.z + battleCoord = true + elseif (origin == "start") then + x, y = self.choregraphy.actor.start.x, self.choregraphy.actor.start.y + battleCoord = true + elseif (origin == "actor") then + x, y = self.choregraphy.actor:getCoordinate() + z = self.choregraphy.actor.z + battleCoord = true + end + if (not battleCoord) then + self.x, self.y = x, y + else + x, y = self.choregraphy.world.map:gridToPixel(x, y, true) + self.x, self.y = x, y - argy - z + end +end + +function QteParent:updateElement(dt) + QteParent.super.updateElement(self, dt) + self.prompts:update(dt) +end + +function QteParent:keypressed(key) + self:verifyPrompts(key) +end + +function QteParent:timerResponse(timer) + if (timer == "qteTimer") then + core.debug:print("qte", "Timer finished") + if (self.timerActive) then + self:finish(self:isSuccessOnEnd()) + end + elseif (timer == "startTimer") then + core.debug:print("qte", "Timer started with " .. self.timer .. " seconds") + self.tweens:newTimer(self.timer, "qteTimer") + self.timerActive = true + self.prompts.defaultTimerValue = 0 + elseif (timer == "endQte") then + self.choregraphy:removeQte() + self:destroy() + end +end + +function QteParent:finish(success) + self.isSuccess = success + self.timerActive = false + self.tweens:newTimer(self.prompts.BEGINTIME, "endQte") + self:endQte() +end + +function QteParent:verifyPrompts(key) + local promptResult = self.prompts:verifyPrompts(key) + if (promptResult == 1) then + self:promptSuccess() + elseif (promptResult == -1) then + self:fail() + end +end + +function QteParent:draw() + self:drawOverButtons() + self.prompts:draw(self.x, self.y) + self:drawUnderButtons() +end + +-- USABLE FUNCTIONS +-- Use these functions to access some of the API + +function QteParent:setTimer(time) + core.debug:print("qte", "Timer started with " .. time .. " prepared") + self.timer = time + self.tweens:newTimer(self.prompts.BEGINTIME, "startTimer") +end + +function QteParent:delay(time) + core.debug:print("qte", "Timer delayed by " .. time .. " seconds") + self.tweens:delayTimer(time, "qteTimer", false) +end + +function QteParent:getTimerInfo() + return self.tweens:getTimerInfo("qteTimer") +end + +function QteParent:success() + self:finish(true) +end + +function QteParent:fail() + self:finish(false) +end + +-- PUBLIC API +-- The functions that the children must overrides + +function QteParent:start() + +end + +function QteParent:update(dt) + -- +end + +function QteParent:promptSuccess() + +end + +function QteParent:isSuccessOnEnd() + return false +end + +function QteParent:drawOverButtons() + +end + +function QteParent:drawUnderButtons() + +end + +return QteParent diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/prompts/button.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/prompts/button.lua new file mode 100644 index 0000000..b6705ee --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/prompts/button.lua @@ -0,0 +1,139 @@ +local Button = Object:extend() +local ButtonCircle = Object:extend() +local TweenManager = require "birb.classes.time" + +local keys = {"A", "B", "C", "select", "up", "down", "left", "right"} +local BTN_SIZE = 21 +local CANVAS_SIZE = 21+2 +local SHAKETIME = 0.02 +local SHAKEPOWER = 4 + +local function myStencilFunction() + love.graphics.circle("fill", CANVAS_SIZE/2, CANVAS_SIZE/2, BTN_SIZE/2 - 1) + end + +function Button:new(prompt, key, number, beginTime) + self.prompt = prompt + self.key = key + self.number = number or 1 + self.showNumber = (self.number > 1) + + self.isPressed = false + + self.lum = 1 + self.opacity = 0 + self.frame = self:getFrame() + self.scale = 1.25 + self.isFailed = false + self.shakeTimer = SHAKETIME + self.shakex, self.shakey = 0, 0 + self.circles = {} + + self.timerTexture = nil + self.tweens = TweenManager(self) + self.tweens:newTween(0, beginTime, {opacity = 1, scale = 1}, "inOutQuart") +end + +function Button:getFrame() + for i, key in ipairs(keys) do + if (key == self.key) then + return i + end + end + error("Non existing key " .. self.key) +end + +function Button:update(dt, isFirst) + self.tweens:update(dt) + for i, circle in ipairs(self.circles) do + circle:update(dt) + end + + if (self.isFailed) then + self.shakeTimer = self.shakeTimer - dt + if (self.shakeTimer < 0) then + self.shakeTimer = SHAKETIME + self.shakex = math.random(SHAKEPOWER*2) - (SHAKEPOWER) + self.shakey = math.random(SHAKEPOWER*2) - (SHAKEPOWER) + end + end + + if (isFirst) then + self.timerTexture = love.graphics.newCanvas(CANVAS_SIZE, CANVAS_SIZE) + love.graphics.setCanvas({self.timerTexture, stencil = true}) + love.graphics.setColor(0.5, 0.5, 0.5, 1) + love.graphics.circle("fill", CANVAS_SIZE/2, CANVAS_SIZE/2, BTN_SIZE/2) + utils.graphics.setColorHSV(self.prompt:getTimer()/3, 1, 1) + love.graphics.stencil(myStencilFunction, "replace", 1) + love.graphics.setStencilTest("greater", 0) + love.graphics.arc("fill", CANVAS_SIZE/2, CANVAS_SIZE/2, BTN_SIZE/2, 0 - (math.pi/2), ((math.pi*2*self.prompt:getTimer()) - (math.pi/2)), 16) + love.graphics.setStencilTest() + love.graphics.setCanvas() + utils.graphics.resetColor() + end +end + +function Button:verifyPrompts(key, removeWhenPressed) + local mustBeRemoved = false + local keyValue = 0 + self.lum = 1 + if (key == self.key) then + keyValue = 1 + self.lum = 0.8 + table.insert(self.circles, ButtonCircle()) + else + keyValue = -1 + self.isFailed = true + end + if (removeWhenPressed and keyValue == 1) then + self.number = self.number - 1 + if (self.number == 0) then + mustBeRemoved = true + end + end + return keyValue, mustBeRemoved +end + +function Button:finish(success) + local scale = 0.75 + if (success == true) then + scale = 1.25 + end + self.tweens:newTween(0, 0.15, {opacity = 0, scale = scale}, "inOutQuart") +end + +function Button:draw(x, y, isFirst) + local x, y = x + self.shakex, y + self.shakey + love.graphics.setColor(1,1,1,self.circleOpacity) + for i, circle in ipairs(self.circles) do + circle:draw(x, y) + end + love.graphics.setColor(self.lum,self.lum,self.lum,self.opacity) + if (isFirst and self.timerTexture ~= nil) then + love.graphics.draw(self.timerTexture, x, y, 0, -self.scale, self.scale, 12, 11) + end + self.prompt.assets.tileset["qtebtn"]:drawTile(self.frame, x, y, 0, self.scale, self.scale, 8, 8) + love.graphics.setColor(1,1,1,1) + if (self.number > 0 and self.showNumber) then + self.prompt.assets.fonts["hudnbrs_small"]:draw(utils.math.numberToString(self.number, 2), x, y + 2, -1, "left") + end +end + +function ButtonCircle:new() + self.radius = 6 + self.opacity = 1 + self.tweens = TweenManager(self) + self.tweens:newTween(0, 0.2, {radius = 12}, "inOutQuart") + self.tweens:newTween(0.1, 0.1, {opacity = 0}, "inOutQuart") +end + +function ButtonCircle:update(dt) + self.tweens:update(dt) +end + +function ButtonCircle:draw(x, y) + love.graphics.setColor(1,1,1,self.opacity) + love.graphics.circle("line",x,y,self.radius, 16) +end + +return Button \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/prompts/init.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/prompts/init.lua new file mode 100644 index 0000000..2584239 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/prompts/init.lua @@ -0,0 +1,65 @@ +local QtePrompts = Object:extend() +local Button = require "scenes.battlesystem.choregraphy.qte.prompts.button" + +QtePrompts.BEGINTIME = 0.2 + +function QtePrompts:new(qte) + self.qte = qte + self.canPress = true + self.removeWhenPressed = true + self.assets = qte.choregraphy.assets + self.scene = core.scenemanager.currentScene + self.current = 1 + self.defaultTimerValue = 1 + + self.list = {} +end + +function QtePrompts:add(key, number) + table.insert(self.list, Button(self, key, number, QtePrompts.BEGINTIME)) +end + +function QtePrompts:getTimer() + local defaultValue = self.defaultTimerValue + local _, _, timerValue = self.qte:getTimerInfo() + return timerValue or defaultValue +end + +function QtePrompts:update(dt) + for i, button in ipairs(self.list) do + button:update(dt, (i == self.current)) + end +end + +function QtePrompts:verifyPrompts(key) + local buttonValue, mustBeRemoved = 0, false + if (self.list[self.current] ~= nil) then + buttonValue, mustBeRemoved = self.list[self.current]:verifyPrompts(key, self.removeWhenPressed) + if (not self.canPress and buttonValue == 1) then + buttonValue = -1 + end + if (mustBeRemoved) then + self.list[self.current]:finish(true) + self.current = self.current + 1 + end + end + for i, button in ipairs(self.list) do + if (buttonValue == -1 and (i ~= self.current)) then + button:finish(false) + end + end + return buttonValue +end + +function QtePrompts:isOver() + return (self.current > #self.list) +end + +function QtePrompts:draw(x, y) + local SIZE = 20 + for i, button in ipairs(self.list) do + button:draw(x + (SIZE*(i-1)) - ((SIZE/2)*(#self.list-1)), y, (i == self.current)) + end +end + +return QtePrompts \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/simpleprompt.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/simpleprompt.lua new file mode 100644 index 0000000..a86b868 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/qte/simpleprompt.lua @@ -0,0 +1,17 @@ +local Parent = require "scenes.battlesystem.choregraphy.qte.parent" +local SimplePrompt = Parent:extend() + +function SimplePrompt:start() + self:setTimer(self.arguments.duration) + for i, keyData in ipairs(self.arguments.key) do + self.prompts:add(keyData[1], keyData[2]) + end +end + +function SimplePrompt:promptSuccess() + if (self.prompts:isOver()) then + self:success() + end +end + +return SimplePrompt \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/addGFX.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/addGFX.lua new file mode 100644 index 0000000..e5439bc --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/addGFX.lua @@ -0,0 +1,29 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local StepGFX = StepParent:extend() + +function StepGFX:new(controller, args) + StepGFX.super.new(self, controller, args, true) +end + +function StepGFX:start() + local x, y, z = self:getStepCoordinate() + + self.choregraphy.world.obj.GFX(self.choregraphy.world, x, y, z, self.arguments.sprite, self, self.arguments.blockProcess, self.tag) + + if (not self.arguments.blockProcess) then + self:finish() + end +end + +function StepGFX:update(dt) + +end + +function StepGFX:getSignal(signal) + if (signal == "gfxEnded") then + self:finish() + end +end + + +return StepGFX diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/addQTE.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/addQTE.lua new file mode 100644 index 0000000..107a652 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/addQTE.lua @@ -0,0 +1,26 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local StepQTE = StepParent:extend() + +function StepQTE:new(controller, args) + StepQTE.super.new(self, controller, args, true) +end + +function StepQTE:start() + self.choregraphy:addQTE(self, self.arguments.origin, self.arguments.qteData, self.arguments.blockProcess, self.tag) + if (not self.arguments.blockProcess) then + self:finish() + end +end + +function StepQTE:update(dt) + +end + +function StepQTE:getSignal(signal) + if (signal == "qteEnded") then + self:finish() + end +end + + +return StepQTE diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/goTo.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/goTo.lua new file mode 100644 index 0000000..fa6a502 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/goTo.lua @@ -0,0 +1,30 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local GoToStep = StepParent:extend() + +function GoToStep:new(controller, args) + GoToStep.super.new(self, controller, args, true) +end + +function GoToStep:start() + local x, y = self:getStepCoordinate() + local actor = self:getActor(self.arguments.who) + + actor:goTo(x, y, self.arguments.duration) + + actor:addTaggedAction(self.tag, self.choregraphy, "goTo") + if (self.arguments.blockProcess == false) then + self:finish() + else + actor:blockChoregraphy(self.arguments.blockProcess, self, "goTo") + end +end + +function GoToStep:update(dt) + +end + +function GoToStep:getSignal(signal) + +end + +return GoToStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/goTo3D.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/goTo3D.lua new file mode 100644 index 0000000..50c9536 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/goTo3D.lua @@ -0,0 +1,30 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local GoTo3DStep = StepParent:extend() + +function GoTo3DStep:new(controller, args) + GoTo3DStep.super.new(self, controller, args, true) +end + +function GoTo3DStep:start() + local x, y, z = self:getStepCoordinate() + local actor = self:getActor(self.arguments.who) + + actor:goTo3D(x, y, z, self.arguments.duration) + actor:addTaggedAction(self.tag, self.choregraphy, "goTo") + + if (self.arguments.blockProcess == false) then + self:finish() + else + actor:blockChoregraphy(self.arguments.blockProcess, self, "goTo") + end +end + +function GoTo3DStep:update(dt) + +end + +function GoTo3DStep:getSignal(signal) + +end + +return GoTo3DStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/init.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/init.lua new file mode 100644 index 0000000..c42a5c0 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/init.lua @@ -0,0 +1,25 @@ +local actions = {} + +local baseURI = "scenes.battlesystem.choregraphy.step." + +actions["addGFX"] = require(baseURI .. "addGFX") +actions["addQTE"] = require(baseURI .. "addQTE") +actions["goTo"] = require(baseURI .. "goTo") +actions["goTo3D"] = require(baseURI .. "goTo3D") +actions["stopMov"] = require(baseURI .. "stopMov") +actions["jumpBack"] = require(baseURI .. "jumpBack") +actions["jump"] = require(baseURI .. "jump") +actions["playSFX"] = require(baseURI .. "playSFX") +actions["sendDamage"] = require(baseURI .. "sendDamage") +actions["sendStatus"] = require(baseURI .. "sendStatus") +actions["setAnimation"] = require(baseURI .. "setAnimation") +actions["setAnimSpeed"] = require(baseURI .. "setAnimSpeed") +actions["wait"] = require(baseURI .. "wait") +actions["waitFor"] = require(baseURI .. "waitFor") +actions["skipTo"] = require(baseURI .. "skipTo") +actions["waitActorFinished"] = require(baseURI .. "waitActorFinished") +actions["useItemEffect"] = require(baseURI .. "useItemEffect") +actions["setCounter"] = require(baseURI .. "setCounter") +actions["startSubChoregraphies"] = require(baseURI .. "startSubChoregraphies") + +return actions diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/jump.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/jump.lua new file mode 100644 index 0000000..7bfd76b --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/jump.lua @@ -0,0 +1,29 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local JumpStep = StepParent:extend() + +function JumpStep:new(controller, args) + JumpStep.super.new(self, controller, args, true) +end + +function JumpStep:start() + local actor = self:getActor(self.arguments.who) + + actor:setJump(self.arguments.power, 0, self.arguments.useDefaultAnimation) + + actor:addTaggedAction(self.tag, self.choregraphy, "jump") + if (self.arguments.blockProcess == false) then + self:finish() + else + actor:blockChoregraphy(self.arguments.blockProcess, self, "jump") + end +end + +function JumpStep:update(dt) + +end + +function JumpStep:getSignal(signal) + +end + +return JumpStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/jumpBack.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/jumpBack.lua new file mode 100644 index 0000000..d0ac080 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/jumpBack.lua @@ -0,0 +1,29 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local JumpBackStep = StepParent:extend() + +function JumpBackStep:new(controller, args) + JumpBackStep.super.new(self, controller, args, true) +end + +function JumpBackStep:start() + local actor = self:getActor(self.arguments.who) + + actor:jumpBack(self.arguments.height, self.arguments.speed) + + actor:addTaggedAction(self.tag, self.choregraphy, "jump") + if (self.arguments.blockProcess == false) then + self:finish() + else + actor:blockChoregraphy(self.arguments.blockProcess, self, "jump") + end +end + +function JumpBackStep:update(dt) + +end + +function JumpBackStep:getSignal(signal) + +end + +return JumpBackStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/parent.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/parent.lua new file mode 100644 index 0000000..43b7f3c --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/parent.lua @@ -0,0 +1,60 @@ +local StepParent = Object:extend() + +function StepParent:new(choregraphySystem, arguments, canBeAsync) + self.choregraphy = choregraphySystem + self.arguments = arguments + self.isStarted = false + self.canBeAsync = (canBeAsync == true) + self.tag = "" +end + +function StepParent:addTag(tag) + if (not utils.string.isEmpty(tag)) then + if (self.canBeAsync) then + core.debug:print("choregraphy/step", "Tag " .. tag .. " added to step.") + self.tag = tag + end + self.choregraphy:startTagAction(tag) + end +end + +function StepParent:updateStep(dt) + if (not self.isStarted) then + self:start() + self.isStarted = true + else + self:update(dt) + end +end + +function StepParent:getActor(name) + return self.choregraphy:getActor(name) +end + +function StepParent:getStepCoordinate() + local argx, argy, argz = self.arguments.x, self.arguments.y, self.arguments.z or 0 + local x, y, z + argx = argx * self.choregraphy.actor.start.direction + local source = self.arguments.origin + + if (source == "start") then + x, y, z = self.choregraphy.actor.start.x, self.choregraphy.actor.start.y, self.choregraphy.actor.start.z + elseif (source == "center") then + x, y, z = 6, 3, 0 + else + local actor = self:getActor(source) + if (actor == nil) then + error("source " .. source .. " not found") + end + x, y, z = actor.x, actor.y, actor.z + end + + return x + argx, y + argy, z + argz +end + +function StepParent:finish() + self.choregraphy:endStep() + self.choregraphy:switchStep() +end + +return StepParent diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/playSFX.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/playSFX.lua new file mode 100644 index 0000000..64c47a5 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/playSFX.lua @@ -0,0 +1,13 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local PlaySFX = StepParent:extend() + +function PlaySFX:new(system, args) + PlaySFX.super.new(self, system, args) +end + +function PlaySFX:start() + self.choregraphy.assets.sfx[self.arguments.sfx]:play() + self:finish() +end + +return PlaySFX diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/sendDamage.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/sendDamage.lua new file mode 100644 index 0000000..5022f5b --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/sendDamage.lua @@ -0,0 +1,20 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local SendDamage = StepParent:extend() + +local maputils = require "scenes.battlesystem.utils" + +function SendDamage:new(system, args) + SendDamage.super.new(self, system, args) +end + +function SendDamage:start() + local power = self.arguments.power + local isSpecial = self.arguments.isSpecial + local type = self.arguments.type + local element = self.arguments.element + + self.choregraphy:sendDamage(power, type, element, isSpecial) + self:finish() +end + +return SendDamage diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/sendStatus.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/sendStatus.lua new file mode 100644 index 0000000..09cc6f6 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/sendStatus.lua @@ -0,0 +1,17 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local SendStatus = StepParent:extend() + +function SendStatus:new(system, args) + SendStatus.super.new(self, system, args) +end + +function SendStatus:start() + local status = self.arguments.status + local force = self.arguments.force + local duration = self.arguments.duration + + self.choregraphy:sendStatus(status, duration, force) + self:finish() +end + +return SendStatus diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setAnimSpeed.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setAnimSpeed.lua new file mode 100644 index 0000000..5168fdd --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setAnimSpeed.lua @@ -0,0 +1,23 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local SetAnimSpeedStep = StepParent:extend() + +function SetAnimSpeedStep:new(controller, args) + SetAnimSpeedStep.super.new(self, controller, args) +end + +function SetAnimSpeedStep:start() + local actor = self:getActor(self.arguments.who) + + actor:setAnimSpeed(self.arguments.speed) + self:finish() +end + +function SetAnimSpeedStep:update(dt) + +end + +function SetAnimSpeedStep:getSignal(signal) + +end + +return SetAnimSpeedStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setAnimation.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setAnimation.lua new file mode 100644 index 0000000..e2790a4 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setAnimation.lua @@ -0,0 +1,29 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local AnimationSetterStep = StepParent:extend() + +function AnimationSetterStep:new(controller, args) + AnimationSetterStep.super.new(self, controller, args, true) +end + +function AnimationSetterStep:start() + local actor = self:getActor(self.arguments.who) + + actor:changeAnimation(self.arguments.animation) + + actor:addTaggedAction(self.tag, self.choregraphy, "animation") + if (self.arguments.blockProcess == false) then + self:finish() + else + actor:blockChoregraphy(self.arguments.blockProcess, self, "animation") + end +end + +function AnimationSetterStep:update(dt) + +end + +function AnimationSetterStep:getSignal(signal) + +end + +return AnimationSetterStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setCounter.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setCounter.lua new file mode 100644 index 0000000..69853b2 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/setCounter.lua @@ -0,0 +1,13 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local SetCounterStep = StepParent:extend() + +function SetCounterStep:new(system, args) + SetCounterStep.super.new(self, system, args) +end + +function SetCounterStep:start() + self.choregraphy:setCounter(self.arguments.counterName, self.arguments.number, self.arguments.relative) + self:finish() +end + +return SetCounterStep diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/skipTo.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/skipTo.lua new file mode 100644 index 0000000..9d05010 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/skipTo.lua @@ -0,0 +1,12 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local SkipToStep = StepParent:extend() + +function SkipToStep:new(system, args) + SkipToStep.super.new(self, system, args) +end + +function SkipToStep:start() + self.choregraphy:skipToStepByTag(self.arguments.skipTo) +end + +return SkipToStep diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/startSubChoregraphies.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/startSubChoregraphies.lua new file mode 100644 index 0000000..a593fb4 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/startSubChoregraphies.lua @@ -0,0 +1,21 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local StartSubchoregraphiesStep = StepParent:extend() + +function StartSubchoregraphiesStep:new(controller, args) + StartSubchoregraphiesStep.super.new(self, controller, args) +end + +function StartSubchoregraphiesStep:start() + self.choregraphy:startSubChoregraphies(self.arguments.waitTime) + if (not self.arguments.blockProcess) then + self:finish() + end +end + +function StartSubchoregraphiesStep:update(dt) + if (not self.choregraphy:hasNextTarget()) then + self:finish() + end +end + +return StartSubchoregraphiesStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/stopMov.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/stopMov.lua new file mode 100644 index 0000000..b5c2c5c --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/stopMov.lua @@ -0,0 +1,23 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local StopMovStep = StepParent:extend() + +function StopMovStep:new(controller, args) + StopMovStep.super.new(self, controller, args, true) +end + +function StopMovStep:start() + local actor = self:getActor(self.arguments.who) + + actor:stopMoving() + self:finish() +end + +function StopMovStep:update(dt) + +end + +function StopMovStep:getSignal(signal) + +end + +return StopMovStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/useItemEffect.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/useItemEffect.lua new file mode 100644 index 0000000..8bce57b --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/useItemEffect.lua @@ -0,0 +1,13 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local UseItemEffect = StepParent:extend() + +function UseItemEffect:new(system, args) + UseItemEffect.super.new(self, system, args) +end + +function UseItemEffect:start() + self.choregraphy:useItemEffect() + self:finish() +end + +return UseItemEffect diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/wait.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/wait.lua new file mode 100644 index 0000000..aede32c --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/wait.lua @@ -0,0 +1,19 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local WaitStep = StepParent:extend() + +function WaitStep:new(controller, args) + WaitStep.super.new(self, controller, args) +end + +function WaitStep:start() + self.timer = 0 +end + +function WaitStep:update(dt) + self.timer = self.timer + dt + if (self.timer > self.arguments.duration) then + self:finish() + end +end + +return WaitStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/waitActorFinished.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/waitActorFinished.lua new file mode 100644 index 0000000..fc7b62f --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/waitActorFinished.lua @@ -0,0 +1,20 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local WaitActorFinishedStep = StepParent:extend() + +function WaitActorFinishedStep:new(controller, args) + WaitActorFinishedStep.super.new(self, controller, args) +end + +function WaitActorFinishedStep:start() + self.choregraphy.actor:blockChoregraphy(true, self, self.arguments.waitFor) +end + +function WaitActorFinishedStep:update(dt) + +end + +function WaitActorFinishedStep:getSignal(signal) + +end + +return WaitActorFinishedStep; diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/waitFor.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/waitFor.lua new file mode 100644 index 0000000..0a33d39 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/step/waitFor.lua @@ -0,0 +1,18 @@ +local StepParent = require "scenes.battlesystem.choregraphy.step.parent" +local WaitForStep = StepParent:extend() + +function WaitForStep:new(controller, args) + WaitForStep.super.new(self, controller, args) +end + +function WaitForStep:start() +end + +function WaitForStep:update(dt) + --print(self.arguments.waitFor) + if (self.choregraphy:checkCondition(self.arguments.waitFor)) then + self:finish() + end +end + +return WaitForStep diff --git a/sonic-bluestreak.love/scenes/battlesystem/choregraphy/subchoregraphy.lua b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/subchoregraphy.lua new file mode 100644 index 0000000..45f0c2d --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/choregraphy/subchoregraphy.lua @@ -0,0 +1,44 @@ +local SubChoregraphy = Object:extend() + +local QteMixin = require "scenes.battlesystem.choregraphy.mixins.qtes" +local StepsMixin = require "scenes.battlesystem.choregraphy.mixins.steps" +local TagsMixin = require "scenes.battlesystem.choregraphy.mixins.tags" +local CountersMixin = require "scenes.battlesystem.choregraphy.mixins.counters" +local WrappersMixin = require "scenes.battlesystem.choregraphy.mixins.wrappers" + +SubChoregraphy:implement(QteMixin) +SubChoregraphy:implement(StepsMixin) +SubChoregraphy:implement(TagsMixin) +SubChoregraphy:implement(CountersMixin) +SubChoregraphy:implement(WrappersMixin) + +function SubChoregraphy:new(parent, target, choregraphy) + self.parent = parent + self:initWrappers(parent.action, target) + + self:initSteps(choregraphy) + self:initQte() + self:initTagActions() + self:initCounters() + + self:register() +end + +function SubChoregraphy:register() + self.parent:registerSubChoregraphy(self) +end + +function SubChoregraphy:update(dt) + self:updateQte(dt) + self:updateSteps(dt) +end + +function SubChoregraphy:endChoregraphy() + self.parent:removeSubChoregraphy(self) +end + +function SubChoregraphy:draw() + self:drawQte() +end + +return SubChoregraphy diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/attack.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/attack.lua new file mode 100644 index 0000000..8c2794d --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/attack.lua @@ -0,0 +1,17 @@ +local ActionParent = require "scenes.battlesystem.fighters.character.actions.parent" +local AttackAction = ActionParent:extend() + +function AttackAction:new(fighter) + AttackAction.super.new(self, fighter) +end + +function AttackAction:needTarget() + return true, true +end + +function AttackAction:startAction() + core.debug:print("cbs/action", "Starting attack action") + self:loadChoregraphy("attack") +end + +return AttackAction diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/defend.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/defend.lua new file mode 100644 index 0000000..04e26ae --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/defend.lua @@ -0,0 +1,20 @@ +local ActionParent = require "scenes.battlesystem.fighters.character.actions.parent" +local DefendAction = ActionParent:extend() + +function DefendAction:new(fighter) + DefendAction.super.new(self, fighter) +end + +function DefendAction:needTarget() + return false, false +end + +function DefendAction:startAction() + core.debug:print("cbs/action", "Starting defend action") + self.fighter.isDefending = true + self.fighter.actor:changeAnimation("defend") + self.fighter.actor.isDefending = true + self:finishAction() +end + +return DefendAction diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/flee.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/flee.lua new file mode 100644 index 0000000..96b605e --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/flee.lua @@ -0,0 +1,34 @@ +local ActionParent = require "scenes.battlesystem.fighters.character.actions.parent" +local FleeAction = ActionParent:extend() +local STATS = require "datas.consts.stats" + +function FleeAction:new(fighter) + FleeAction.super.new(self, fighter) +end + +function FleeAction:needTarget() + return false, false +end + +function FleeAction:startAction() + core.debug:print("cbs/action", "Starting flee action") + local stats = self.fighter.abstract.stats + + if (self.fighter.abstract.name == "shadow") then + self.fighter.turnSystem.scene:showMessage("You won't flee the battle") + self:finishAction() + return + end + + local chanceToFlee = self.fighter.turnSystem:getChanceTooFlee(self.fighter:getStat(STATS.SPEED)) + if (math.random(100) < chanceToFlee) then + self.fighter.turnSystem.scene:showMessage("You flee the battle") + self.fighter.turnSystem:fleeBattle() + else + self.fighter.turnSystem.scene:showMessage("You failed to flee the battle") + self:finishAction() + end + +end + +return FleeAction diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/init.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/init.lua new file mode 100644 index 0000000..d351d2d --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/init.lua @@ -0,0 +1,9 @@ +local actions = {} + +actions.attack = require "scenes.battlesystem.fighters.character.actions.attack" +actions.skill = require "scenes.battlesystem.fighters.character.actions.skill" +actions.item = require "scenes.battlesystem.fighters.character.actions.item" +actions.defend = require "scenes.battlesystem.fighters.character.actions.defend" +actions.flee = require "scenes.battlesystem.fighters.character.actions.flee" + +return actions diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/item.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/item.lua new file mode 100644 index 0000000..316130a --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/item.lua @@ -0,0 +1,28 @@ +local ActionParent = require "scenes.battlesystem.fighters.character.actions.parent" +local ItemAction = ActionParent:extend() +local EffectManager = require "game.loot.effectManager" + +function ItemAction:new(fighter, category, item) + ItemAction.super.new(self, fighter) + self.category = category + self.item = item + self.itemdata = core.datas:get("items", item) + self.effectManager = EffectManager() + self.effectManager:getItemData(category, item) +end + +function ItemAction:needTarget() + return (not self.itemdata.affectEverybody), (self.category == "wisps") +end + +function ItemAction:useItemEffect() + self.effectManager:applyEffectsBattle(self.target) +end + +function ItemAction:startAction() + core.debug:print("cbs/action", "Starting item action") + self:loadChoregraphy("useitem") + game.loot:removeItem(self.category, self.item, 1) +end + +return ItemAction diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/parent.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/parent.lua new file mode 100644 index 0000000..6f624c0 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/parent.lua @@ -0,0 +1,56 @@ +local ActionParent = Object:extend() + +local ChoregraphySystem = require "scenes.battlesystem.choregraphy" + +function ActionParent:new(fighter) + self.fighter = fighter + self.target = nil + self.choregraphy = nil + + self.isStarted = false +end + +function ActionParent:update(dt) + if (self.choregraphy ~= nil) then + self.choregraphy:update(dt) + end +end + +function ActionParent:loadChoregraphy(skillname) + local skill = core.datas:get("skills", skillname) + self:loadChoregraphyFromSkill(skill) +end + +function ActionParent:loadChoregraphyFromSkill(skill) + self.choregraphy = ChoregraphySystem(self, skill.choregraphy, skill.subChoregraphy) +end + +function ActionParent:needTarget() + -- needTarget, targetEnnemies + return false, false +end + +function ActionParent:setTarget(target) + self.target = target +end + +function ActionParent:start() + self.isStarted = true + self:startAction() +end + +function ActionParent:choregraphyEnded() + self.choregraphy = nil + self:finishAction() +end + +function ActionParent:startAction() + + self:finishAction() +end + +function ActionParent:finishAction() + self.fighter:finishAction() +end + +return ActionParent diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/skill.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/skill.lua new file mode 100644 index 0000000..e1c3605 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/actions/skill.lua @@ -0,0 +1,19 @@ +local ActionParent = require "scenes.battlesystem.fighters.character.actions.parent" +local SkillAction = ActionParent:extend() + +function SkillAction:new(fighter, skill) + self.data = core.datas:get("skills", skill) + SkillAction.super.new(self, fighter) +end + +function SkillAction:needTarget() + return (self.data.targetNumber == 1), self.data.targetEnnemies +end + +function SkillAction:startAction() + core.debug:print("cbs/action", "Starting flee action") + self:loadChoregraphyFromSkill(self.data) + self.fighter:setPP(self.data.cost * -1, true) +end + +return SkillAction diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/init.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/init.lua new file mode 100644 index 0000000..1d52b4c --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/init.lua @@ -0,0 +1,131 @@ +local FighterParent = require "scenes.battlesystem.fighters.fighter" +local HeroFighter = FighterParent:extend() + +local SelectionSystem = require "scenes.battlesystem.fighters.character.selection" +local actionList = require "scenes.battlesystem.fighters.character.actions" + +local HEROES_LINE = 2; + +function HeroFighter:new(owner, character, id) + self.name = character + self.super.new(self, owner, true, id) + + self:initVoices() + + self.exp = self.abstract.exp +end + +function HeroFighter:update(dt) + HeroFighter.super.update(self, dt) +end + +function HeroFighter:getAbstract() + return game.characters.list[self.name] +end + +function HeroFighter:createActor() + local x, y = HEROES_LINE, ((self.id-1)*(4/(#game.characters.team-1))+1) + local hero = self.world.obj.Hero(self.world, x, y, self) + if (self.abstract.hp <= 0) then + hero:setAsKo() + end + return hero +end + +function HeroFighter:startAction() + core.debug:print("cbs/heroFighter", "launching the action menu") + self.action = nil + self:talk("turnstart") + self.turnSystem.scene.gui.screens["hud"]:buildMenu( self ) +end + +function HeroFighter:endAction() + +end + +-- Basic actions +function HeroFighter:doNothing() + self:setInactive() +end + +function HeroFighter:doBasicAction(action) + self.action = actionList[action](self) + self:verifyTargets() +end + +function HeroFighter:useItem(category, item) + self.action = actionList["item"](self, category, item) + self:verifyTargets() +end + +function HeroFighter:useSkill(skill) + self.action = actionList["skill"](self, skill) + self:verifyTargets() +end + +function HeroFighter:verifyTargets() + local needTarget, targetEnnemies = self.action:needTarget() + + if (needTarget) then + if (targetEnnemies) then + SelectionSystem(self, self.owner.turnSystem.ennemies, true) + else + SelectionSystem(self, self.owner, false) + end + else + self.action:start() + end + +end + +function HeroFighter:attack() + self:doBasicAction("attack") +end + +function HeroFighter:receiveTarget(target) + if (self.action ~= nil) then + self.action:setTarget(target) + self.action:start() + end +end + +function HeroFighter:goBackToMenu() + self.turnSystem.scene.gui:setFocus("battleMenu") +end + +-- LIFE functions +function HeroFighter:updatePP() + local elem = self.turnSystem.scene.gui:getElement(self.abstract.name .. "StatutBar") + elem:updatePP() +end + +function HeroFighter:updateHP() + local elem = self.turnSystem.scene.gui:getElement(self.abstract.name .. "StatutBar") + elem:updateHP() +end + +-- VOICE SYSTEM + +function HeroFighter:initVoices() + self:addVoiceEffect("move") + self:addVoiceEffect("turnstart") +end + +function HeroFighter:addVoiceEffect(name) + local completename = self.name .. "_" .. name + local path = "datas/gamedata/characters/" .. self.name .. "/voices/" .. name .. ".wav" + self.assets:newSFX(completename, path) +end + +function HeroFighter:talk(name) + local completename = self.name .. "_" .. name + self.assets.sfx[completename]:play() +end + +-- DRAW FUNCTIONS +function HeroFighter:drawIcon(x, y) + local iconID = self.abstract.data.icon + self.assets.tileset["charicons"]:drawTile(iconID, x, y) +end + +return HeroFighter diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/character/selection.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/selection.lua new file mode 100644 index 0000000..1040b7c --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/character/selection.lua @@ -0,0 +1,66 @@ +local GuiElement = require "birb.modules.gui.elements.parent" +local SelectionSystem = GuiElement:extend() + +function SelectionSystem:new(owner, fighterSide, onlyAlive) + SelectionSystem.super.new(self, "selection", 0, 0, 1, 1) + self.fighterList = fighterSide:getTargets(onlyAlive) + self.owner = owner + self.assets = self.owner.assets + self.selectedTarget = 1 + self:updateTarget() + self:getFocus() +end + +function SelectionSystem:keypressed(key) + if (key == "A") then + self.assets.sfx["mSelect"]:play() + self:selectTarget() + elseif (key == "B") then + self.assets.sfx["mBack"]:play() + self:goBack() + elseif (key == "up") then + self:purgeTarget() + if (self.selectedTarget == 1) then + self.selectedTarget = #self.fighterList + else + self.selectedTarget = self.selectedTarget - 1 + end + self.assets.sfx["mBeep"]:play() + self:updateTarget() + elseif (key == "down") then + self:purgeTarget() + if (self.selectedTarget == #self.fighterList) then + self.selectedTarget = 1 + else + self.selectedTarget = self.selectedTarget + 1 + end + self.assets.sfx["mBeep"]:play() + self:updateTarget() + end +end + +function SelectionSystem:purgeTarget() + local target = self.fighterList[self.selectedTarget] + target.actor.isSelected = false +end + +function SelectionSystem:updateTarget() + local target = self.fighterList[self.selectedTarget] + target.actor.isSelected = true +end + +function SelectionSystem:selectTarget() + self:looseFocus() + self:destroy() + self:purgeTarget() + self.owner:receiveTarget(self.fighterList[self.selectedTarget]) +end + +function SelectionSystem:goBack() + self:looseFocus() + self:destroy() + self:purgeTarget() + self.owner:goBackToMenu() +end + +return SelectionSystem diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemies.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemies.lua new file mode 100644 index 0000000..bb6a335 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemies.lua @@ -0,0 +1,52 @@ +local FighterControllerParent = require "scenes.battlesystem.fighters.parent" +local EnnemyController = FighterControllerParent:extend() + +local Villain = require "scenes.battlesystem.fighters.ennemy" +local STATS = require "datas.consts.stats" + +function EnnemyController:new(owner, battleData) + self.super.new(self, owner) + self:initVillains(battleData) +end + +function EnnemyController:initVillains(battleData) + for i,ennemyBaseData in ipairs(battleData.ennemies) do + local ennData = core.datas:parse("ennemytype", ennemyBaseData) + if (ennData.type == "normal") then + self:addVillain(ennData) + elseif (ennData.type == "boss") then + self:addBoss(ennData) + else + core.debug:warning("unknown type " .. ennData.type) + end + end +end + +function EnnemyController:addVillain(ennData) + for i=1, ennData.number do + self:add(Villain(self, ennData.category, ennData.name, self:count() + 1)) + end +end + +function EnnemyController:getHighestSpeed() + local highestSpeed = 0 + for i, villain in ipairs(self.list) do + local currentSpeed = villain:getStat(STATS.SPEED) + if (currentSpeed > highestSpeed) then + highestSpeed = currentSpeed + end + end + return highestSpeed +end + +function EnnemyController:addBoss(ennData) + local boss = Villain(self, ennData.category, ennData.name, self:count() + 1) + boss:setBonus(ennData.pvFactor, ennData.statFactor) + boss.isBoss = true + boss:setCheapEffect(ennData.cheapEffect) + self.turnSystem.canFleeBattle = false + self:add(boss) + boss:createHPBar() +end + +return EnnemyController diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/action.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/action.lua new file mode 100644 index 0000000..b561001 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/action.lua @@ -0,0 +1,22 @@ +local ActionParent = require "scenes.battlesystem.fighters.character.actions.parent" +local EnnemyAction = ActionParent:extend() + +function EnnemyAction:new(fighter, skill) + self.data = core.datas:get("badskills", skill) + EnnemyAction.super.new(self, fighter) +end + +function EnnemyAction:needTarget() + return (self.data.targetNumber == 1), self.data.targetEnnemies +end + +function EnnemyAction:startAction() + core.debug:print("cbs/action", "Starting flee action") + self:loadChoregraphyFromSkill(self.data) +end + +function EnnemyAction:getData() + return self.data +end + +return EnnemyAction diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/init.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/init.lua new file mode 100644 index 0000000..ee42910 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/init.lua @@ -0,0 +1,5 @@ +local folder = "scenes.battlesystem.fighters.ennemy.behaviours." + +return { + ["random"] = require(folder .. "random") +} diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/parent.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/parent.lua new file mode 100644 index 0000000..52c2b92 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/parent.lua @@ -0,0 +1,61 @@ +local BehaviourParent = Object:extend() + +function BehaviourParent:new(fighter, skilldata, targetList, highestScore) + self.fighter = fighter + self.scoreList = {} + self.targetList = targetList + self.skilldata = skilldata + self.highestScore = highestScore + + self:initScoreList() + self:calculateAllScores() +end + +function BehaviourParent:initScoreList() + for i, target in ipairs(self.targetList) do + self.scoreList[target.name] = 0 + end +end + +function BehaviourParent:calculateAllScores() + for i, target in ipairs(self.targetList) do + self.scoreList[target.name] = self:calculateScore(target) + end +end + +function BehaviourParent:calculateScore(target) + return 0 +end + +function BehaviourParent:getScore(target) + return self.scoreList[target.name] +end + +function BehaviourParent:isBestTarget(target, bestTargetScore, isHighest) + if (bestTargetScore == nil) then + return true + else + if (isHighest) then + return (self:getScore(target) >= bestTargetScore) + else + return (self:getScore(target) <= bestTargetScore) + end + end +end + +function BehaviourParent:getTarget() + local bestTargetScore = nil + local finalTarget = nil + + for i, target in ipairs(self.targetList) do + if (self:isBestTarget(target, bestTargetScore, self.isHighest)) then + finalTarget = target + bestTargetScore = self:getScore(target) + end + end + + return finalTarget +end + + +return BehaviourParent diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/random.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/random.lua new file mode 100644 index 0000000..b79c4ce --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/behaviours/random.lua @@ -0,0 +1,12 @@ +local ParentBehaviour = require "scenes.battlesystem.fighters.ennemy.behaviours.parent" +local RandomBehaviour = ParentBehaviour:extend() + +function RandomBehaviour:new(fighter, skilldata, targetList) + RandomBehaviour.super.new(self, fighter, skilldata, targetList, true) +end + +function RandomBehaviour:calculateScore(target) + return math.random(1, 200) +end + +return RandomBehaviour diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/init.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/init.lua new file mode 100644 index 0000000..100479a --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/ennemy/init.lua @@ -0,0 +1,110 @@ +local FighterParent = require "scenes.battlesystem.fighters.fighter" +local VillainFighter = FighterParent:extend() + +local SimpleHPBar = require "game.modules.gui.simplehpbar" +local BossHPBar = require "scenes.battlesystem.gui.hudelements.bosshpbar" +local EnnemyAction = require "scenes.battlesystem.fighters.ennemy.action" +local behaviourList = require "scenes.battlesystem.fighters.ennemy.behaviours" + +local POSITIONS = {1, 3, 5} +local ENNEMY_LINE = 11; + +function VillainFighter:new(owner, category, ennemy, id) + self.name = ennemy + self.category = category + self.super.new(self, owner, false, id) + + self.hpbar = SimpleHPBar(self.abstract.hp) + self.isBoss = false +end + +function VillainFighter:setCheapEffect(cheapEffect) + self.actor:setCheapEffect(cheapEffect) +end + +function VillainFighter:updateAssets(dt) + self.hpbar:update(dt) +end + +function VillainFighter:getAbstract() + return game.ennemies:getEnnemyData(self.category, self.name) +end + +function VillainFighter:createActor() + local x, y = ENNEMY_LINE, POSITIONS[self.id] + return self.world.obj.Ennemy(self.world, x, y, self) +end + +function VillainFighter:startAction() + core.debug:print("cbs/villainFighter", "choosing an action") + self.action = nil + self:selectAction() +end + +function VillainFighter:selectAction() + if (#self.abstract.skills < 1) then + self:finishAction() + else + local skillId = math.floor(math.random(1, #self.abstract.skills)) + local skill = self.abstract.skills[skillId] + self.action = EnnemyAction(self, skill) + self:verifyTargets() + end +end + +function VillainFighter:verifyTargets() + local needTarget, targetEnnemies = self.action:needTarget() + + if (needTarget) then + if (targetEnnemies) then + --fighter, skilldata, targetList + local Behaviour = behaviourList[self.abstract.data.behaviour] + local behav = Behaviour(self, self.action:getData(), self.owner.turnSystem.player:getTargets(true)) + self.action:setTarget(behav:getTarget()) + self.action:start() + else + --self.selection = SelectionSystem(self, self.owner, false) + end + else + self.action:start() + end + +end + + +function VillainFighter:endAction() + +end + +function VillainFighter:setBonus(pvFactor, statFactor) + self.abstract:setBonus(pvFactor, statFactor) +end + +-- LIFE FUNCTIONS +function VillainFighter:setHP(value, relative) + VillainFighter.super.setHP(self, value, relative) + self.hpbar:setHP(self.abstract.hp) + if (self.bossHpBar ~= nil) then + self.bossHpBar:setHP(self.abstract.hp) + end +end + +-- DRAW FUNCTIONS +function VillainFighter:drawIcon(x, y) + self.assets.images["badnicsIcon"]:draw(x-1, y-2) + self.assets.fonts["hudnbrs_small"]:print(self.id, x+10, y+8) +end + +function VillainFighter:drawOversprite(x, y) + if (not self.isBoss) then + self.hpbar:draw(x, y) + else + self.assets.images["crown"]:draw(x, y - 2) + end +end + +function VillainFighter:createHPBar() + self.bossHpBar = BossHPBar(self.abstract.hp) +end + +return VillainFighter diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/fighter.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/fighter.lua new file mode 100644 index 0000000..b2eb8e4 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/fighter.lua @@ -0,0 +1,267 @@ +local FighterParent = Object:extend() + +local battleutils = require "game.utils.battle" +local STATS = require "datas.consts.stats" + +function FighterParent:new(owner, isHero, id) + self.owner = owner + self.turnSystem = owner.turnSystem + self.world = owner.world + self.isHero = isHero + self.assets = self.turnSystem.scene.assets + + -- Note : l'ID est ici relatif à chaque quand, il n'est donc pas unique, + -- ce qui est unique étant le combo id + isHero + self.id = id + + self.abstract = self:getAbstract() + self.actor = self:createActor() + + self.isActive = false + self.isAlive = true + + self.isDefending = false + + self.action = nil + self.statsBonus = {} +end + +-- LIFE handling functions + +function FighterParent:setHP(value, relative) + local relativeNumber = value + if (not relative) then + relativeNumber = relative - self.abstract.hp + end + self.abstract:setHP(value, relative) + self.actor:setDamageNumber(relativeNumber) + self:updateHP() +end + +function FighterParent:setPP(value, relative) + self.abstract:setPP(value, relative) + self:updatePP() +end + +function FighterParent:applyDeath() + if (self.abstract:isAlive() ~= self.isAlive ) then + if (self.abstract:isAlive()) then + self:revive() + else + self:die() + end + end +end + +function FighterParent:revive() + self.isAlive = true + self.isDefending = false + self.actor:revive() +end + +function FighterParent:die() + self.isAlive = false + self.actor:die() +end + +function FighterParent:updatePP() + -- Fonction vide +end + +function FighterParent:updateHP() + -- Fonction vide +end + +function FighterParent:haveProtecType(type) + return self.abstract:haveProtecType(type) +end + +function FighterParent:sendDamageToAll(listTarget, value, type, element, isSpecial) + for _, target in ipairs(listTarget) do + self:sendDamage(target, value, type, element, isSpecial) + end +end + +function FighterParent:sendStatusToAll(listTarget, status, duration, force) + for _, target in ipairs(listTarget) do + self:sendStatus(target, status, duration, force) + end +end + +function FighterParent:getTargets(ourSide) + if (self.isHero == ourSide) then + return self.turnSystem.player:getTargets(true) + else + return self.turnSystem.ennemies:getTargets(true) + end +end + +function FighterParent:sendDamage(target, value, type, element, isSpecial) + local damage = battleutils.computeLaunchingDamages(value, self, isSpecial) + + core.debug:print("cbs/battler", "Sending " .. damage .." damage at " .. target.name) + if (battleutils.rollDice(self:getStat(STATS.ACCURACY))) then + return target:receiveDamage(damage, type, element, isSpecial, self) + else + target.actor:avoidedAttack() + return false + end +end + +function FighterParent:sendStatus(target, status, duration, force) + core.debug:print("cbs/battler", "Sending status " .. status .." at " .. target.name) + if ((not force) or battleutils.rollDice(self:getStat(STATS.ACCURACY))) then + target:receiveStatus(status, duration, force) + end +end + +function FighterParent:receiveStatus(status, duration, force) + if (force or (not battleutils.rollDice(self:getStat(STATS.LUCK)))) then + self.abstract:addStatut(status, duration) + end +end + +function FighterParent:receiveDamage(value, type, element, isSpecial, fromWho) + local damages = battleutils.computeReceivingDamages(value, self, isSpecial, self.isDefending) + damages = battleutils.applyProtectTypes(damages, type, self.abstract:getProtecTypes()) + damages = battleutils.applyResistences(damages, element, self.abstract:getResistences()) + damages = battleutils.applyWeaknesses(damages, element, self.abstract:getWeaknesses()) + + if (battleutils.rollDice(self:getStat(STATS.EVASION))) then + self.actor:avoidedAttack() + return false + else + self:applyDamage(damages) + end + + return true +end + +function FighterParent:applyDamage(damage) + core.debug:print("cbs/fighter", "Taken " .. damage .. " damage" ) + self:setHP(damage * -1, true) + self.owner:registerDamage(damage) + if (not self.isDefending) then + self.actor:getHurt() + end + if (not self.abstract:isAlive()) then + self.owner:registerKO() + end +end + +function FighterParent:getAbstract() + return {} +end + +function FighterParent:createActor() + return {} +end + +function FighterParent:update(dt) + if (self.action ~= nil) then + if (self.action.isStarted) then + self.action:update(dt) + end + end +end + +function FighterParent:updateAssets(dt) + -- Vide pour l'instant +end + +function FighterParent:setActive() + self.isActive = true + if (self.isDefending) then + self.actor:changeAnimation("idle") + self.actor.isDefending = false + end + self:startAction() +end + +function FighterParent:applyRegen() + local regenStat = self:getStat(STATS.HPREGEN) + if (regenStat ~= 0) then + self:setHP(regenStat*self:getStat(STATS.HPMAX)/100, true) + end + + local regenStat = self:getStat(STATS.PPREGEN) + if (regenStat ~= 0) then + self:setPP(regenStat*self:getStat(STATS.PPMAX)/100, true) + end +end + +function FighterParent:setInactive() + self.isActive = false + self:applyRegen() + self.turnSystem:endAction() +end + +function FighterParent:getNbrActionPerTurn() + return self.abstract.turns +end + +function FighterParent:getStat(statname) + local stat = (self.abstract.stats:get(statname) * self:getStatBonusValue(statname)) + self.abstract:getStatutsStat(statname) + if (self.abstract:haveStatuts("cursed") and (statname == "evasion")) then + return math.max(0, stat) + end + return stat +end + +function FighterParent:getStatBonusValue(statname) + if (utils.table.contain(STATS.NOBONUS, statname)) then + return 1 + else + return STATS.BONUS[self:getStatBonus(statname) + 5] + end +end + +function FighterParent:getStatBonus(statname) + return self.statsBonus[statname] or 0 +end + +function FighterParent:setStatBonus(statname, value, relative) + local statBonus = 0 + if (relative) then + statBonus = self:getStatBonus(statname) + end + self.statsBonus[statname] = math.max(-4, math.min(statBonus + value, 4)) +end + +function FighterParent:getStats() + return self.abstract:getStats() +end + +function FighterParent:startAction() + +end + +function FighterParent:finishAction() + self.action = nil + self:setInactive() +end + +function FighterParent:getUniqueIdentificator() + local side = 1 + if (self.isHero == false) then + side = -1 + end + return self.id * side +end + +function FighterParent:getNonUniqueIdentificator() + return self.id +end + +function FighterParent:canFight() + return self.isAlive +end + +-- DRAW FUNCTIONS + +function FighterParent:drawIcon(x, y) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.rectangle("fill", x, y, 16, 16) +end + +return FighterParent diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/parent.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/parent.lua new file mode 100644 index 0000000..dac26f2 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/parent.lua @@ -0,0 +1,104 @@ +local FighterControllerParent = Object:extend() + +function FighterControllerParent:new(turnSystem) + self.turnSystem = turnSystem + self.world = turnSystem.world + self.list = {} + self.damages = 0 + self.ko = 0 +end + +function FighterControllerParent:get(id) + return self.list[id] +end + +function FighterControllerParent:getList() + return self.list +end + +function FighterControllerParent:add(fighter) + table.insert(self.list, fighter) +end + +function FighterControllerParent:count() + return #self.list +end + +function FighterControllerParent:registerDamage(damage) + self.damages = math.floor(self.damages + damage) +end + +function FighterControllerParent:registerKO() + self.ko = self.ko + 1 +end + +function FighterControllerParent:countAlive() + local aliveCount = 0 + for i, fighter in ipairs(self.list) do + if (fighter:canFight()) then + aliveCount = aliveCount + 1 + end + end + return aliveCount +end + +function FighterControllerParent:getTargets(onlyAlive) + local targetList = {} + for i, fighter in ipairs(self.list) do + if (fighter:canFight() or (not onlyAlive)) then + table.insert(targetList, fighter) + end + end + return targetList +end + +function FighterControllerParent:applyDeath() + for i, fighter in ipairs(self.list) do + fighter:applyDeath() + end + return self:countAlive() +end + +function FighterControllerParent:setActive(activeActor) + self.activeActor = activeActor + activeActor:setActive() +end + +function FighterControllerParent:update(dt) + for i, fighter in ipairs(self.list) do + fighter:updateAssets(dt) + end +end + +function FighterControllerParent:endAction() + self.owner:nextAction() +end + +function FighterControllerParent:putActions(actionList) + for i, fighter in ipairs(self.list) do + + for i=1, fighter:getNbrActionPerTurn() do + local action = {} + action.fighter = fighter + action.number = i + table.insert(actionList, action) + end + + end +end + +function FighterControllerParent:removeFighter(fighterToRemove) + -- remove the actor from the battler liste + for i, fighter in ipairs(self.list) do + if fighter == fighterToRemove then + table.remove(self.list, i) + end + end + + -- Also remove all actions related to the actor + self.turnSystem:removeAllActionsFromFighter(fighterToRemove) +end + + + +return FighterControllerParent diff --git a/sonic-bluestreak.love/scenes/battlesystem/fighters/player.lua b/sonic-bluestreak.love/scenes/battlesystem/fighters/player.lua new file mode 100644 index 0000000..a569d21 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/fighters/player.lua @@ -0,0 +1,23 @@ +local FighterControllerParent = require "scenes.battlesystem.fighters.parent" +local HeroFighterController = FighterControllerParent:extend() + +local Character = require "scenes.battlesystem.fighters.character" + +function HeroFighterController:new(owner) + self.super.new(self, owner) + self:initHeroes() +end + +function HeroFighterController:initHeroes() + for i, hero in ipairs(game.characters.team) do + self:add(Character(self, hero, i)) + end +end + +function HeroFighterController:fleeBattle() + for i, hero in ipairs(self.list) do + hero.actor:flee() + end +end + +return HeroFighterController diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/bosshpbar.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/bosshpbar.lua new file mode 100644 index 0000000..1485650 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/bosshpbar.lua @@ -0,0 +1,30 @@ +local GuiElement = require "birb.modules.gui.elements.parent" +local BossHpBar = GuiElement:extend() + +local ComplexHPBar = require "game.modules.gui.complexhpbar" + +local POS_X, POS_Y = 280, 28 + +function BossHpBar:new(hp) + self.hp = hp + self.baseHP = hp + self.hpbar = ComplexHPBar(120) + self.hpbar:setColorForeground(248/255, 160/255, 0, 1) + self.hpbar:setColorBackground(112/255, 0, 0) + + self.bossTexture = love.graphics.newImage("assets/gui/strings/boss.png") + local w, h = self.bossTexture:getDimensions() + + BossHpBar.super.new(self, "BossHPBar", POS_X, POS_Y, w, h) +end + +function BossHpBar:setHP(newHP) + self:newTween(0, 0.1, {hp = newHP}, 'inCubic') +end + +function BossHpBar:draw() + self.hpbar:draw(self.x, self.y, self.hp / self.baseHP) + love.graphics.draw(self.bossTexture, self.x + 98, self.y + 10) +end + +return BossHpBar \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/menu.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/menu.lua new file mode 100644 index 0000000..0be7f2b --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/menu.lua @@ -0,0 +1,86 @@ +local Parent = require "game.modules.gui.fancymenu" +local BattleMenu = Parent:extend() + +local defTransitions = require "birb.modules.transitions" +local radTransitions = require "game.modules.transitions" + +local MENU_X, MENU_Y = 88, 72 +local MENU_W = 180-32 +local MENU_ITEM_NUMBER = 6 + +function BattleMenu:new() + BattleMenu.super.new(self, "battleMenu", MENU_X, MENU_Y, MENU_W, MENU_ITEM_NUMBER, true) + self.isVisible = false +end + +function BattleMenu:rebuild(character) + self:clear() + self:addItem("Attack", "left", function() self:doAction(character, "attack") end) + self:generateSubmenu("skills", "Skill", "main", character.abstract.skills, function(data) return self:createSkillWidget(character, data) end, true) + self:createItemMenus(character) + self:switch("main") + self:addItem("Defend", "left", function() self:doAction(character, "defend") end) + self:addItem("Flee", "left", function() self:doAction(character, "flee") end) + self:getFocus() + self.canvas.needRedraw = true +end + +function BattleMenu:createItemMenus(character) + self:addSubmenu("items", "Items", "main", true) + for i,pocket in ipairs(game.loot.inventory) do + if (pocket.inBattle) then + self:generateSubmenu(pocket.name, pocket.fullname, "items", pocket.list, + function(itemInBag) + return self:createItemWidget(character, pocket.name, itemInBag) + end, true) + end + end +end + +function BattleMenu:createSkillWidget(character, skill) + local data = core.datas:get("skills", skill.name) + local isOk = (data.cost <= character.abstract.pp) + + local cost = {utils.math.numberToString(data.cost or 0, 2), "right"} + local color = utils.math.either(isOk, {1, 1, 1}, {1, 0.3, 0.3}) + local sfx = utils.math.either(isOk, "select", "error") + local func = function() self:doSkill(character, skill.name, isOk) end + + --text, position, func, type, additionnalItems, color + return character.abstract:getSkillName(skill.name), "left", func, sfx, {cost}, color +end + +function BattleMenu:createItemWidget(character, pocketName, itemInBag) + local data = core.datas:get("items", itemInBag.name) + local nbr = game.loot:getItemNumber(pocketName, itemInBag.name) + local nbrLabel = {"x" .. utils.math.numberToString(nbr, 2), "right"} + local func = function() self:useItem(character, pocketName, itemInBag.name) end + + --text, position, func, type, additionnalItems, color + return data.fullname, "left", func, "select", {nbrLabel}, {1, 1, 1} +end + + +function BattleMenu:doAction(character, action) + self:looseFocus() + self.isVisible = false + character:doBasicAction(action) +end + +function BattleMenu:useItem(character, pocketName, item) + self:looseFocus() + self.isVisible = false + character:useItem(pocketName, item) +end + +function BattleMenu:doSkill(character, skill, isOk) + if (isOk) then + self:looseFocus() + character:useSkill(skill) + self.isVisible = false + else + self.scene:showMessage("You haven't enough PP!") + end +end + +return BattleMenu diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/statutbar.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/statutbar.lua new file mode 100644 index 0000000..2754ebe --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/statutbar.lua @@ -0,0 +1,68 @@ +local GuiElement = require "birb.modules.gui.elements.parent" +local StatusBar = GuiElement:extend() +local TweenManager = require "birb.classes.time" + +local Emblem = require "game.modules.gui.emblem" +local ComplexHPBar = require "game.modules.gui.complexhpbar" + +local DIST_STATUSBAR = 106 +local Y = 200 +local STATUSBAR_W = 90 + +function StatusBar:new(fighter, i) + self:initAbstract(fighter) + StatusBar.super.new(self, self.abstract.name .. "StatutBar", (i-0.5)*DIST_STATUSBAR-(STATUSBAR_W/2), Y, STATUSBAR_W, 64) + self:createParts(self.scene) +end + +function StatusBar:initAbstract(fighter) + self.abstract = fighter.abstract + self.hp = self.abstract.hp + self.pp = self.abstract.pp + self.stats = self.abstract:getStats() +end + +function StatusBar:createParts(scene) + self.emblem = Emblem(self.abstract, scene) + + self.hpbar = ComplexHPBar(58) + self.ppbar = ComplexHPBar(58) + self.hpbar:setColorForeground(248 / 255, 160 / 255, 0, 1) + self.hpbar:setColorBackground(112 / 255, 0, 0) + self.ppbar:setColorForeground(0, 248 / 255, 248 / 255, 1) + self.ppbar:setColorBackground(0, 54 / 255, 229 / 255) +end + +function StatusBar:updateHP() + self.tweens:newTween(0, 0.3, {hp = self.abstract.hp}, "linear") +end + +function StatusBar:updatePP() + self.tweens:newTween(0, 0.3, {pp = self.abstract.pp}, "linear") +end + +function StatusBar:draw() + self.emblem:drawBackground(self.x, self.y) + self:drawStatusArea(self.x + 10, self.y - 8) + self.emblem:drawForeground(self.x, self.y) +end + +function StatusBar:drawStatusArea(x, y) + self.assets.images["statusbar"]:draw(x, y) + + local hpmax = self.stats:get(self.stats.HPMAX) + local ppmax = self.stats:get(self.stats.PPMAX) + + self.assets.fonts["hudnbrs_small"]:set() + self.hpbar:drawWithLabels(x + 6, y + 9, self.hp, hpmax) + self.ppbar:drawWithLabels(x + 18, y + 21, self.pp, ppmax) + + local lvl = self.abstract.level + + if lvl < 100 then + lvl = "0" .. lvl + end + love.graphics.print(lvl, x + 42, y + 1) +end + +return StatusBar diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/turnbar.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/turnbar.lua new file mode 100644 index 0000000..2618d2d --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/hudelements/turnbar.lua @@ -0,0 +1,27 @@ +local Parent = require "birb.modules.gui.elements.parent" +local TurnBar = Parent:extend() + +local gui = require "game.modules.gui" + +function TurnBar:new() + TurnBar.super.new(self, "turnbar", 76, 5, 1, 1) + self.turns = self.scene.turns + self.cursor = self.turns.turns.current +end + +function TurnBar:draw() + for i, action in ipairs(self.turns.actionList) do + if action.fighter:canFight() then + action.fighter:drawIcon(self.x + (i-1)*(20), self.y) + else + gui.drawEmptyIcon(self.x + (i-1)*(20), self.y) + end + end + local cursorx = (self.cursor-1) * 20 + + if #self.turns.actionList > 0 then + self.assets.images["menucursor"]:draw(self.x + cursorx, self.y, math.rad(90), 1, 1, 4, 16) + end +end + +return TurnBar \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/init.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/init.lua new file mode 100644 index 0000000..9302615 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/init.lua @@ -0,0 +1,42 @@ +local GuiScreen = require "birb.modules.gui.screen" +local CbsScreen = GuiScreen:extend() + +local StatutBar = require "scenes.battlesystem.gui.hudelements.statutbar" +local TurnBar = require "scenes.battlesystem.gui.hudelements.turnbar" +local BattleMenu = require "scenes.battlesystem.gui.hudelements.menu" + +local Composite = require "birb.modules.gui.elements.composite" +local Counter = require "birb.modules.gui.elements.counter" +local Asset = require "birb.modules.gui.elements.assets" + +local show = { + {"turns", "movement", 0.5, 0.6, 424/2, 80, "inOutQuart"}, +} + +function CbsScreen:new() + CbsScreen.super.new(self, "hud") + self:show() +end + +function CbsScreen:buildMenu(character) + self.elements["battleMenu"]:rebuild(character) +end + +function CbsScreen:createElements() + local turns = self.scene.turns + local list = { + {Composite("turns", 10, 10, { + {Asset("turnImg", "images", "hudturn", -1, -1), 0, 0}, + {Counter("turnCnt", "hudnbrs", turns.turns, "number", 2, -1, -1), 33, 1}, + {TurnBar(), 62, -3}, + }), 0}, + {BattleMenu(), 0} + } + for i, fighter in ipairs(turns.player:getList()) do + table.insert(list, {StatutBar(fighter, i), 0}) + end + + return list +end + +return CbsScreen \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/victory/exp.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/exp.lua new file mode 100644 index 0000000..0c2d9d2 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/exp.lua @@ -0,0 +1,80 @@ +local GuiElement = require "birb.modules.gui.elements.parent" +local CharacterExp = GuiElement:extend() + +local gui = require "game.modules.gui" +local charutils = require "game.utils.characters" + +function CharacterExp:new(x, y, character, number) + self.character = character + self.started = false + self.done = false + CharacterExp.super.new(self, character.name .. "Exp", x, y, 1, 1) + self.opacity = 0 + self.number = number + self:newTween(1.4, 0.4, {opacity = 1}, "inExpo") + if self.number == 1 then + self:startInSeconds(2.5) + end + self.targetExp = self.scene.turns.rewards:getExp(character) + self.exp = character.abstract.exp +end + +function CharacterExp:update(dt) + if (not self.done and (self.started)) then + self:addCharacterExp(dt) + end +end + +function CharacterExp:startInSeconds(seconds) + self:newFunc(seconds, "startMe", function() self:startExpGain(1) end) +end + +function CharacterExp:startExpGain(number) + self.started = true +end + +function CharacterExp:addCharacterExp(dt) + local level = self.character.abstract.level + local xpAddRatio = charutils.getLevelExpRange(level) * 0.5 + local newExp = self.exp + (xpAddRatio * dt) + + if (newExp < self.targetExp) then + self.exp = newExp + local nextLevelExp = charutils.getExpValue(level + 1) + if (self.exp >= nextLevelExp) then + self.character.abstract.abstract:levelUp() + end + else + self.exp = self.targetExp + self.character.abstract.exp = self.targetExp + self.done = true + self.isLast = self.screen:nextExp(self.number + 1) + if (self.isLast) then + self:getFocus() + end + end +end + +function CharacterExp:keypressed(key) + if (key == "A" and self.done and self.isLast) then + self.scene:returnToOverworld(false) + self.scene:setPrompt("") + end +end + +function CharacterExp:draw() + love.graphics.setColor(1, 1, 1, self.opacity) + self.assets.images["expbar"]:draw(self.x, self.y) + self.character:drawIcon(self.x + 1, self.y + 6) + love.graphics.setColor(0, 0.8, 0.1, self.opacity) + local level = self.character.abstract.level + local exp = self.exp + local remainingExp = charutils.getRemainingExp(exp, level) + local expRatio = charutils.getRelativeExpValue(exp, level) / charutils.getLevelExpRange(level) + gui.drawBar(self.x + 22, self.y + 11, math.floor(56 * expRatio), 7) + love.graphics.setColor(1, 1, 1, self.opacity) + self.assets.fonts["hudnbrs_small"]:print(math.floor(remainingExp), self.x + 71, self.y + 11, "right") + self.assets.fonts["hudnbrs_small"]:print(level, self.x + 72, self.y + 1, "right") +end + +return CharacterExp \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/victory/init.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/init.lua new file mode 100644 index 0000000..3607e4d --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/init.lua @@ -0,0 +1,122 @@ +local Screen = require "birb.modules.gui.screen" +local VictoryScreen = Screen:extend() + +local TextElement = require "birb.modules.gui.elements.text" +local ChoiceElement = require "game.modules.gui.choiceElem" +local ConfirmDialog = require "game.modules.confirmdialog" +local TextureElement = require "birb.modules.gui.elements.drawable" +local LootElement = require "scenes.battlesystem.gui.victory.loot" +local ItemsElement = require "scenes.battlesystem.gui.victory.items" +local CharExperience = require "scenes.battlesystem.gui.victory.exp" +local TileElement = require "birb.modules.gui.elements.tile" + +local defTransitions = require "birb.modules.transitions" +local gui = require "game.modules.gui" + +local HEIGHT = 32 +local STARTX, STARTY = 32, HEIGHT + 44 +local ENDX, ENDY = 424 - 32, 240 - 24 +local SIZE_FEATS = 128+28 +local START_ITEMS = STARTX + SIZE_FEATS +local START_EXP = START_ITEMS + 128 + +local show = { + {"gameText", "movement", 0.9, 0.4, 424/2, HEIGHT, "inExpo"}, + --{"rankBox", "tween", 1.4, 0.4, {opacity = 1}, "inExpo"}, + {"loot", "tween", 1.4, 0.4, {opacity = 1}, "inExpo"}, + {"items", "tween", 1.4, 0.4, {opacity = 1}, "inExpo"}, + } + +function VictoryScreen:new() + self.feats = 0 + self.rankBox = gui.newTextBox("assets/gui/dialogbox.png", 48, 32) + self.itemBox = gui.newTextBox("assets/gui/dialogbox.png", 96, 48) + + VictoryScreen.super.new(self, "titleScreen") + self:addTransform("show", show) + self.scene:showOverlay(true) + self:show() +end + +function VictoryScreen:createFeats(list) + local ennemyNbr, turns, dmgSent, dmgTaken, ko = self.turns:getDatas() + self:addFeat(list,"Ennemies", ennemyNbr) + self:addFeat(list,"Turns", turns) + self:addFeat(list,"Dmg sent", dmgSent) + if (dmgTaken == 0) then + self:addFeat(list,"No damage !", "") + else + self:addFeat(list,"Dmg taken", dmgTaken) + self:addFeat(list,"KO", ko) + end + local qteRate, haveDoneQte = self.rewards:getQteSuccessRate() + if (not haveDoneQte) then + self:addFeat(list,"No QTE done") + else + self:addFeat(list,"QTE success", math.floor(qteRate * 100) .. "%") + end + self:addRank(list) +end + +function VictoryScreen:addFeat(list, text, label) + self.feats = self.feats + 1 + local featID = "feat" .. self.feats + + label = label or "" + + local elem = ChoiceElement(featID, text, "", label, STARTX - 16, STARTY + (16*(self.feats-1)), SIZE_FEATS) + elem.opacity = 0 + elem:newTween(1 + (0.2*self.feats), 0.15, {opacity = 1, x = STARTX}, 'inQuad') + + table.insert(list, {elem, 0, 1}) +end + +function VictoryScreen:addRank(list) + local rank = TileElement("rank", "ranks", self.rewards:getRank(), 424/2, ENDY - 28,0,4,4,13,13, 0) + rank:newTween(1.9, 0.4, {sx=1, sy=1, opacity=1}, 'inExpo') + + table.insert(list, {rank, 0, 1}) +end + +function VictoryScreen:nextExp(nbr) + local list = self.scene.turns.player:getList() + local nextChar = list[nbr] + if nextChar ~= nil then + self.elements[nextChar.name .. "Exp"]:startExpGain(nbr) + return false + else + self.scene:setPrompt("Finish") + return true + end +end + +function VictoryScreen:createElements() + self.turns = self.scene.turns + self.rewards = self.turns.rewards + + local list = { + {TextElement("gameText", "SA2font", "BATTLE COMPLETED", 424/2, -24, "center"), 0, 1}, + --{TextureElement("rankBox", self.rankBox, 424/2, ENDY - 4, 0, 1,1, 64/2,48, 0), 0, 1}, + {LootElement(START_ITEMS + 2, STARTY - 2), 0, 1}, + {ItemsElement(START_ITEMS + 2, STARTY + 40, {"test", "test", "test"}), 0, 1} + } + self:createFeats(list) + + for i, character in ipairs(self.scene.turns.player:getList()) do + table.insert(list, {CharExperience(START_EXP - 4, STARTY + (i-1)*24 - 12, character, i), 0, 1}) + end + + return list +end + +function VictoryScreen:returnToTitle() + core.screen:startTransition(defTransitions.default, defTransitions.circle, function() scenes.menus.title(true) end, 424/2, 240/2) +end + +function VictoryScreen:loadLastSave() + self.scene.tweens:newTween(0, 0.3, {borderPosition=0}, "inOutQuad") + core.screen:startTransition(defTransitions.default, defTransitions.default, function() game:reload() scenes.overworld() end, 424/2, 240/2) +end + + +return VictoryScreen \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/victory/items.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/items.lua new file mode 100644 index 0000000..dbc4641 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/items.lua @@ -0,0 +1,23 @@ +local CanvasElement = require "birb.modules.gui.elements.canvas" +local ItemsElement = CanvasElement:extend() + +local gui = require "game.modules.gui" + +function ItemsElement:new(x, y, list) + self.background = gui.newTextBox("assets/gui/dialogbox.png", 128, 40+16) + local w, h = self.background:getDimensions() + ItemsElement.super.new(self, "items", x, y, w, h) + self.opacity = 0 + self.list = list +end + +function ItemsElement:drawTexture() + love.graphics.draw(self.background, 0, 0) + for index, value in ipairs(self.list) do + if (index <= 4) then + self.assets.fonts["small"]:draw(value, 8, 4 + (16*(index-1)), -1, "left") + end + end +end + +return ItemsElement \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/gui/victory/loot.lua b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/loot.lua new file mode 100644 index 0000000..eb7c661 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/gui/victory/loot.lua @@ -0,0 +1,22 @@ +local CanvasElement = require "birb.modules.gui.elements.canvas" +local LootElement = CanvasElement:extend() + +local gui = require "game.modules.gui" + +function LootElement:new(x, y) + self.background = gui.newTextBox("assets/gui/dialogbox.png", 128, 40) + local w, h = self.background:getDimensions() + LootElement.super.new(self, "loot", x, y, w, h) + self.canvas.isAnimated = true + self.opacity = 0 +end + +function LootElement:drawTexture() + love.graphics.draw(self.background, 0, 0) + self.assets.fonts["small"]:draw("Rings: ", 8, 4, -1, "left") + self.assets.fonts["small"]:draw("0", self.w - 8, 4, -1, "right") + self.assets.fonts["small"]:draw("Exp: ", 8, 20, -1, "left") + self.assets.fonts["small"]:draw("0", self.w - 8, 20, -1, "right") +end + +return LootElement \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/battlesystem/init.lua b/sonic-bluestreak.love/scenes/battlesystem/init.lua new file mode 100644 index 0000000..43c0713 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/init.lua @@ -0,0 +1,86 @@ +local Scene = require "game.scenes" + +local BattleSystem = Scene:extend() + +local World = require "scenes.battlesystem.world" +local Turns = require "scenes.battlesystem.turns" + +local VictoryScreen = require "scenes.battlesystem.gui.victory" +local GameOverScreen = require "game.modules.gui.gameover" + +local CbsScreen = require "scenes.battlesystem.gui" + +local TweenManager = require "birb.classes.time" + +function BattleSystem:new(battleData) + BattleSystem.super.new(self) + self.assets:batchImport("assets.battle") + + self:playMusic(battleData.music) + self:initManagers(battleData) + self:startBattle() + + CbsScreen() + + self.screen = nil + self.tweens = TweenManager(self) +end + +function BattleSystem:playMusic(music) + self.assets:setMusic("assets/music/" .. music .. ".mp3") + self.assets:playMusic() +end + +function BattleSystem:initManagers(battleData) + self.datas = {} + self.world = World(self) + self.turns = Turns(self, battleData) +end + +function BattleSystem:startBattle() + self.turns:startBattle() +end + +function BattleSystem:finishBattle() + self.assets:setMusic("assets/music/victory.mp3") + self.assets:playMusic() + VictoryScreen(self) +end + +function BattleSystem:fleeBattle() + self.tweens:newTimer(2, "flee") +end + +function BattleSystem:timerResponse(name) + if (name == "flee") then + self:returnToOverworld(true) + end +end + +function BattleSystem:returnToOverworld(isFleeing) + self.assets:silence() + game.cbs:endBattle(isFleeing) +end + +function BattleSystem:looseBattle() + GameOverScreen(self) +end + +function BattleSystem:haveMenus() + return self.gui.elements["battleMenu"].isVisible +end + +function BattleSystem:update(dt) + self.tweens:update(dt) + self.turns:update(dt) + self.world:update(dt) +end + +function BattleSystem:exit() + self.world:destroy() + self.battlearena = nil + + collectgarbage() +end + +return BattleSystem diff --git a/sonic-bluestreak.love/scenes/battlesystem/rewards.lua b/sonic-bluestreak.love/scenes/battlesystem/rewards.lua new file mode 100644 index 0000000..75e030e --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/rewards.lua @@ -0,0 +1,79 @@ +local Rewards = Object:extend() + +local rankFactor = {1, 1.25, 1.5, 1.75, 2} + +function Rewards:new(turns) + self.turns = turns + self.qte = 0 + self.qteSuccess = 0 +end + +function Rewards:apply() + local _, rings = self:getRewards(true) + game.loot.rings = game.loot.rings + rings +end + +function Rewards:getRank() + local ennemyNbr, turns, _, _, ko = self.turns:getDatas() + local qteSuccess, haveDoneQte = self:getQteSuccessRate() + local rank = 3 + + if (not haveDoneQte) then + rank = 3 + elseif (qteSuccess >= 0.75) then + rank = 4 + elseif (qteSuccess >= 0.5) then + rank = 3 + elseif (qteSuccess >= 0.25) then + rank = 2 + else + rank = 1 + end + + -- TODO: modifier l'effet de nombre de tour pour les boss + if (turns/ennemyNbr > 3) then + rank = rank - 1 + end + + if (ko == 0) then + rank = rank + 1 + end + + return math.max(1, math.min(5, rank)) +end + +function Rewards:getExp(character) + local exp = self:getRewards(true) + return character.abstract.exp + exp +end + +function Rewards:getRewards(real) + local exp, ring = 0, 0 + for i, ennemy in ipairs(self.turns.ennemies.list) do + exp = exp + ennemy.abstract.data.giveExp + ring = ring + ennemy.abstract.data.giveRings + end + + if (real) then + exp = exp * rankFactor[self:getRank()] + ring = ring * rankFactor[self:getRank()] + end + + return exp, ring +end + +function Rewards:getQteSuccessRate() + if (self.qte == 0) then + return 0, false + end + return self.qteSuccess/self.qte, true +end + +function Rewards:addQTE(success) + self.qte = self.qte + 1 + if (success) then + self.qteSuccess = self.qteSuccess + 1 + end +end + +return Rewards diff --git a/sonic-bluestreak.love/scenes/battlesystem/turns.lua b/sonic-bluestreak.love/scenes/battlesystem/turns.lua new file mode 100644 index 0000000..eed59fa --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/turns.lua @@ -0,0 +1,170 @@ +local TurnController = Object:extend() + +local Player = require "scenes.battlesystem.fighters.player" +local Ennemy = require "scenes.battlesystem.fighters.ennemies" + +local Rewards = require "scenes.battlesystem.rewards" + +local maputils = require "scenes.battlesystem.utils" + +function TurnController:new(scene, battleData) + self.scene = scene + self.world = scene.world + + self.isActive = false + + self.currentlyPlaying = "" + + self.turns = {} + self.turns.current = 1 + self.turns.number = 0 + self.turns.isFinished = true + self.turns.changeBattler = true + self.actionList = {} + + self.currentFighter = nil + + self.canFleeBattle = true + + self.gui = self.scene.gui + + self.player = Player(self) + self.ennemies = Ennemy(self, battleData) + + self.rewards = Rewards(self) + + -- Change the seed at the start of each battle + math.randomseed( os.time() ) + self:applyDeath() +end + +function TurnController:getChanceTooFlee(value) + if (self.canFleeBattle) then + local speedComparison = math.min(value / self.ennemies:getHighestSpeed(), 1.5) + return 25 + (50 * speedComparison) + end + return 0 +end + +function TurnController:fleeBattle() + self.player:fleeBattle() + self.scene:fleeBattle() +end + +function TurnController:startBattle() + self.isActive = true +end + +function TurnController:finishBattle() + self.isActive = false + self.actionlist = {} + self.scene:finishBattle() + self.rewards:apply() +end + +function TurnController:looseBattle() + self.isActive = false + self.actionlist = {} + self.scene:looseBattle() +end + +function TurnController:update(dt) + self.player:update(dt) + self.ennemies:update(dt) + if (self.isActive) then + if (self.currentFighter ~= nil) then + self.currentFighter:update(dt) + else + if (self.player:countAlive() > 0) then + self:nextAction() + else + self:looseBattle() + end + end + end +end + +function TurnController:getRank() + return self.rewards:getRank() +end + +function TurnController:getRewards() + return self.rewards:getRewards(false) +end + +function TurnController:getDatas() + local ennemyNbr = #self.ennemies.list + local turns = self.turns.current + local dmgSent = self.ennemies.damages + local dmgTaken = self.player.damages + local ko = self.player.ko + return ennemyNbr, turns, dmgSent, dmgTaken, ko +end + +function TurnController:nextAction() + if (self.turns.isFinished) or (self.turns.current >= #self.actionList) then + self:startNewTurn() + else + self.turns.current = self.turns.current + 1 + core.debug:print("cbs/turns", "switching to next action") + end + + self:startAction() +end + +function TurnController:startNewTurn() + core.debug:print("cbs/turns", "New Turn Starting") + self.turns.current = 1 + self.turns.isFinished = false + self.turns.number = self.turns.number + 1 + self:calculateTurn() +end + +function TurnController:calculateTurn() + self.actionList = {} + self.player:putActions(self.actionList) + self.ennemies:putActions(self.actionList) + table.sort(self.actionList, maputils.sortBattlers) +end + +function TurnController:removeAllActionsFromFighter(fighterToRemove) + for i, action in ipairs(self.actionlist) do + if action.fighter == fighterToRemove then + table.remove(self.actionlist, i) + end + end +end + +function TurnController:applyDeath() + local ennemiesAlive = self.ennemies:applyDeath() + if (ennemiesAlive == 0) then + self:finishBattle() + end + self.player:applyDeath() +end + + +function TurnController:startAction() + core.debug:print("cbs/turns", "Starting action " .. self.turns.current) + local nextAction = self.actionList[self.turns.current] + local nextFighter = nextAction.fighter + if (not nextFighter:canFight()) then + -- On skipe le personnage s'il a été detruit + self:nextAction() + else + self.currentFighter = nextFighter + core.debug:print("cbs/turns", "Activating " .. self.currentFighter.name) + self.currentFighter:setActive() + self.gui:newTween("turnbar", 0, 0.2, {cursor = self.turns.current}, 'inCubic') + end +end + +function TurnController:endAction() + self.currentFighter = nil +end + +function TurnController:sendSignalToCurrentBattler(signal, subSignal) + self.actionList[self.turns.current].actor:receiveSignal(signal, subSignal) +end + +return TurnController diff --git a/sonic-bluestreak.love/scenes/battlesystem/utils.lua b/sonic-bluestreak.love/scenes/battlesystem/utils.lua new file mode 100644 index 0000000..dd1eeb8 --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/utils.lua @@ -0,0 +1,24 @@ +local maputils = {} +local STATS = require "datas.consts.stats" + +maputils.CONST = {} + +maputils.CONST.STARTX = -8 +maputils.CONST.STARTY = 90 + +function maputils.sortBattlers(a, b) + local aspeed = a.fighter:getStat(STATS.SPEED) / (3 ^ (a.number-1)) + local bspeed = b.fighter:getStat(STATS.SPEED) / (3 ^ (b.number-1)) + + if (aspeed == bspeed) then + if (a.fighter.isHero == b.fighter.isHero) then + return (a.fighter.id < b.fighter.id) + else + return a.fighter.isHero + end + else + return (aspeed > bspeed) + end +end + +return maputils diff --git a/sonic-bluestreak.love/scenes/battlesystem/world.lua b/sonic-bluestreak.love/scenes/battlesystem/world.lua new file mode 100644 index 0000000..41d5cce --- /dev/null +++ b/sonic-bluestreak.love/scenes/battlesystem/world.lua @@ -0,0 +1,100 @@ +local World = Object:extend() + +local Map = require "game.modules.drawing.parallaxBackground" + +local HEIGHT = 5 +local BORDER_BOTTOM = 2 + +-- INIT FUNCTIONS +-- Initialize the battle world + +function World:new(scene, battlefile) + self.scene = scene + self.assets = scene.assets + + self.obj = require "scenes.battlesystem.actors" + + self.actors = {} + self.globalID = 0 + + self.map = Map(scene, HEIGHT, BORDER_BOTTOM, "city") + self.index = {} + + self.isBattleActive = false +end + +function World:registerActor(actor) + self.globalID = self.globalID + 1 + + table.insert(self.actors, actor) + actor.id = self.globalID +end + +function World:destroyActor(actorToDestroy) + for i, actor in ipairs(self.actors) do + if actor == actorToDestroy then + table.remove(self.actors, i) + end + end +end + +-- INFO FUNCTIONS +-- Get info from the world + +function World:caseIsEmpty(x, y, notThisActor) + local actor = self:getActorInCase(x, y, notThisActor) + + return (actor == nil) +end + +function World:getActorInCase(x, y, notThisActor) + for i, actor in ipairs(self.actors) do + if (actor.x == x) and (actor.y == y) and (actor ~= notThisActor) then + core.debug:print("cbs/world", "one actor found in case <" .. x .. ";" .. y .. ">") + return actor + end + end + + return nil +end + +function World:getActorByName(name) + return self.index[name] +end + +-- UPDATE FUNCTION +-- Update all actors + +function World:update(dt) + for i, actor in ipairs(self.actors) do + actor:update(dt) + end +end + +function World:sendSignalToCurrentBattler(signal, subSignal) + self.scene.turns:sendSignalToCurrentBattler(signal, subSignal) +end + +-- DRAW FUNCTION +-- Draw the world + +function World:draw() + self.map:draw() + self:drawShadows() + self:drawActors() +end + +function World:drawActors() + table.sort(self.actors, function(a, b) return (a.y < b.y) end) + for i, actor in ipairs(self.actors) do + actor:draw() + end +end + +function World:drawShadows() + for i, actor in ipairs(self.actors) do + actor:drawShadow() + end +end + +return World diff --git a/sonic-bluestreak.love/scenes/init.lua b/sonic-bluestreak.love/scenes/init.lua index e1563ab..fd9789c 100644 --- a/sonic-bluestreak.love/scenes/init.lua +++ b/sonic-bluestreak.love/scenes/init.lua @@ -1,5 +1,7 @@ return { - test = require "scenes.test_scene", - title = require "scenes.titlescreen", - boost = require "scenes.subgame.sonic-boost" + test = require "scenes.subgames.testBattle", + test2 = require "scenes.subgames.testShoot", + cbs = require "scenes.battlesystem", + menus = require "scenes.menus", + overworld = require "scenes.overworld" } diff --git a/sonic-bluestreak.love/scenes/menus/commons/menu.lua b/sonic-bluestreak.love/scenes/menus/commons/menu.lua new file mode 100644 index 0000000..e5da981 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/commons/menu.lua @@ -0,0 +1,76 @@ +local menu = {} + +local RadianceListMenu = require "game.modules.menus.fancy" +local defTransitions = require "birb.modules.transitions" + +menu.MainMenu = RadianceListMenu.FancyMenu:extend() +menu.DebugMenu = RadianceListMenu.FancyMenu:extend() +menu.SceneWidget = RadianceListMenu.BaseWidget:extend() + +local CONST = {} +CONST.MENU = {} +CONST.MENU.X = 16 +CONST.MENU.Y = 48 +CONST.MENU.W = 424/2 +CONST.MENU.ITEM_NUMBER = 8 + +-- Basic menu structure +function menu.MainMenu:new(scene, name) + local x, y = CONST.MENU.X, CONST.MENU.Y + local w = CONST.MENU.W / 1.5 + local itemNumber = CONST.MENU.ITEM_NUMBER + menu.MainMenu.super.new(self, scene, name, x, y, w, itemNumber, false) +end + +function menu.DebugMenu:new(scene, name) + local x, y = CONST.MENU.X, CONST.MENU.Y + local w = CONST.MENU.W + local itemNumber = CONST.MENU.ITEM_NUMBER + menu.DebugMenu.super.new(self, scene, name, x, y, w, itemNumber, false) +end + +function menu.DebugMenu:setPanel(panel, panelArgument) + self.panel = panel + self.panelArgument = panelArgument +end + +function menu.DebugMenu:activationAction() + if (self.panel ~= nil) then + self.scene.panel = self.panel(self.panelArgument) + end +end + +function menu.DebugMenu:clone(name) + return menu.DebugMenu(self.scene, name) +end + +function menu.DebugMenu:draw() + love.graphics.setColor(0, 0, 0, 0.5) + love.graphics.rectangle("fill", self.x, self.y, self.w, self.h) + utils.graphics.resetColor() + menu.DebugMenu.super.draw(self) +end + +-- SceneWidget +function menu.SceneWidget:new(scene, menuName, newScene, newSceneName, sceneArgument) + menu.SceneWidget.super.new(self, scene, menuName, newSceneName, "") + self.newScene = newScene + self.sceneArgument = sceneArgument +end + +function menu.SceneWidget:action() + self.scene.assets:playSFX("mSelect") + self.scene:flushKeys() + if (self.sceneArgument ~= nil) then + core.screen:startTransition(defTransitions.default, defTransitions.default, + function() self.newScene(self.sceneArgument) end, + 0, 0) + else + core.screen:startTransition(defTransitions.default, defTransitions.default, + function() self.newScene() end, + 0, 0) + end +end + + +return menu diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/animation/init.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/animation/init.lua new file mode 100644 index 0000000..023f999 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/animation/init.lua @@ -0,0 +1,61 @@ +local Scene = require "game.scenes" +local menu = require "scenes.menus.debugmenus.animation.menu" + +local CharAnimViewer = Scene:extend() +local Background = require "game.modules.drawing.parallaxBackground" +local Sprite = require "birb.modules.assets.types.sprites" + + +function CharAnimViewer:new() + CharAnimViewer.super.new(self) + self.assets:batchImport("assets.debug") + local mainMenu = menu.commons.DebugMenu(self, "MainMenu") + + self:setBackground("city") + + for charName, _ in pairs(game.characters.list) do + mainMenu:addSubMenu(charName, charName) + local sprite = Sprite("datas/gamedata/characters/" .. charName .. "/sprites") + for animName, _ in pairs(sprite.data.animations) do + menu.AnimationWidget(self, charName, animName) + end + end + menu.commons.SceneWidget(self, "MainMenu", scenes.menus.main, "Back") + + self.menusystem:activate() + self.menusystem:switchMenu("MainMenu") + + self.sprite = nil +end + +function CharAnimViewer:constructMenu() + +end + +function CharAnimViewer:setSpriteAndAnim(character, animationName) + self.sprite = Sprite("datas/gamedata/characters/" .. character .. "/sprites") + self.sprite:changeAnimation(animationName, true) +end + + +function CharAnimViewer:update(dt) + if (love.keyboard.isDown("z") and (not self.menusystem.isActive)) then + self.menusystem:activate() + end + if (self.sprite ~= nil) then + self.sprite:update(dt) + end +end + +function CharAnimViewer:setBackground(newBackground) + self.background = Background(self, 5, 1, newBackground) +end + +function CharAnimViewer:draw() + self.background:draw() + if (self.sprite ~= nil) then + self.sprite:draw(424/2, 240/1.5) + end +end + +return CharAnimViewer diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/animation/menu.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/animation/menu.lua new file mode 100644 index 0000000..1fe81b5 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/animation/menu.lua @@ -0,0 +1,19 @@ +local commons = require "scenes.menus.commons.menu" +local listMenu = require "game.modules.menus.list" +local menu = {} +menu.commons = commons +menu.AnimationWidget = listMenu.DualTextWidget:extend() + +-- ShowBackground +function menu.AnimationWidget:new(scene, menuName, animName) + menu.AnimationWidget.super.new(self, scene, menuName, animName, "") + self.charName = menuName + self.animName = animName +end + +function menu.AnimationWidget:action() + self.scene:setSpriteAndAnim(self.charName, self.animName) + self.scene.menusystem:deactivate() +end + +return menu diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/battleBack/init.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/battleBack/init.lua new file mode 100644 index 0000000..7928d32 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/battleBack/init.lua @@ -0,0 +1,40 @@ +local Scene = require "game.scenes" +local menu = require "scenes.menus.debugmenus.battleBack.menu" + +local BackgroundViewer = Scene:extend() +local Background = require "game.modules.drawing.parallaxBackground" +local backgroundList = require "datas.gamedata.maps.shoot.zones" + + +function BackgroundViewer:new() + BackgroundViewer.super.new(self) + self.assets:batchImport("assets.debug") + menu.commons.DebugMenu(self, "MainMenu") + + self:setBackground("city") + + for backId, backgroundData in pairs(backgroundList) do + menu.ShowBackgroundWidget(self, "MainMenu", backgroundData.name, backId) + end + menu.commons.SceneWidget(self, "MainMenu", scenes.menus.main, "Back") + + self.menusystem:activate() + self.menusystem:switchMenu("MainMenu") +end + + +function BackgroundViewer:update(dt) + if (love.keyboard.isDown("z") and (not self.menusystem.isActive)) then + self.menusystem:activate() + end +end + +function BackgroundViewer:setBackground(newBackground) + self.background = Background(self, 5, 1, newBackground) +end + +function BackgroundViewer:draw() + self.background:draw() +end + +return BackgroundViewer diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/battleBack/menu.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/battleBack/menu.lua new file mode 100644 index 0000000..9927170 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/battleBack/menu.lua @@ -0,0 +1,19 @@ +local commons = require "scenes.menus.commons.menu" +local listMenu = require "game.modules.menus.list" +local menu = {} +menu.commons = commons +menu.ShowBackgroundWidget = listMenu.DualTextWidget:extend() + +-- ShowBackground +function menu.ShowBackgroundWidget:new(scene, menuName, backgroundName, backgroundId) + menu.ShowBackgroundWidget.super.new(self, scene, menuName, backgroundName, "") + self.backgroundId = backgroundId +end + +function menu.ShowBackgroundWidget:action() + self.scene:setBackground(self.backgroundId) + self.scene.menusystem:deactivate() +end + + +return menu diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/init.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/init.lua new file mode 100644 index 0000000..8105301 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/init.lua @@ -0,0 +1,102 @@ +local Scene = require "game.scenes" +local menu = require "scenes.menus.debugmenus.choregraphy.menu" + +local ChoregraphyViewer = Scene:extend() + +local World = require "scenes.battlesystem.world" +local Fighter = require "scenes.menus.debugmenus.choregraphy.mocks.fighter" + +function ChoregraphyViewer:new() + ChoregraphyViewer.super.new(self) + self.assets:batchImport("assets.battle") + self.world = World(self) + + self:buildMenu() + self:buildMocks() +end + +-- MENU FUNCTIONS +function ChoregraphyViewer:buildMenu() + menu.commons.DebugMenu(self, "MainMenu") + + self:buildCharacterMenu() + + self.menusystem.menus["MainMenu"]:finalize() + self.menusystem:activate() + self.menusystem:switchMenu("MainMenu") + menu.commons.SceneWidget(self, "MainMenu", scenes.menus.main, "Back") +end + +function ChoregraphyViewer:buildCharacterMenu() + for i,category in ipairs(core.datas:getCategories("ennemies")) do + self:buildEnnemyListMenu(category) + end + + self:addSubMenu("characters", "MainMenu", "Rivals") + for k, character in pairs(game.characters.list) do + self:addSubMenu(k, "characters", character.fullname) + menu.HeroChoregraphyWidget(self, k, core.datas:get("skills", "attack")) + self:buildSkillMenu(k) + end +end + +function ChoregraphyViewer:buildEnnemyListMenu(category) + self:addSubMenu(category, "MainMenu", category) + for i,ennemy in ipairs(core.datas.getFromCategory("ennemies", category)) do + self:buildEnnemySkillMenu(category, ennemy) + end +end + +function ChoregraphyViewer:buildEnnemySkillMenu(category, ennemy) + self:addSubMenu(ennemy, category, ennemy) + local data = core.datas:get("ennemies", ennemy) + for j,skillName in ipairs(data.skills) do + if (core.datas:exists("badskills", skillName)) then + menu.EnnemyChoregraphyWidget(self, category, ennemy, core.datas:get("badskills", skillName)) + end + end +end + +function ChoregraphyViewer:buildSkillMenu(charName) + local skillList = require("datas.gamedata.characters." .. charName .. ".skills") + local skillTreated = {} + for i,skill in ipairs(skillList) do + local skillName = skill[1] + if (skillTreated[skillName] ~= true) then + skillTreated[skillName] = true + if (core.datas:exists("skills", skillName)) then + menu.HeroChoregraphyWidget(self, charName, core.datas:get("skills", skillName)) + end + end + end +end + +function ChoregraphyViewer:addSubMenu(submenu, parent, name) + local parent = parent or "MainMenu" + self.menusystem.menus[parent]:addSubMenu(submenu, name) +end + +-- MOCKS FUNCTIONS +function ChoregraphyViewer:buildMocks() + self.fighter = Fighter(self) +end + +function ChoregraphyViewer:playHeroChoregraphy(character, data) + self.fighter:playHeroChoregraphy(character, data) +end + +function ChoregraphyViewer:playEnnemyChoregraphy(category, ennemy, data) + self.fighter:playEnnemyChoregraphy(category, ennemy, data) +end + +-- OTHER +function ChoregraphyViewer:update(dt) + self.fighter:update(dt) + self.world:update(dt) +end + +function ChoregraphyViewer:draw() + +end + +return ChoregraphyViewer diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/menu.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/menu.lua new file mode 100644 index 0000000..9ef4fac --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/menu.lua @@ -0,0 +1,34 @@ +local commons = require "scenes.menus.commons.menu" +local listMenu = require "game.modules.menus.list" +local menu = {} +menu.commons = commons +menu.HeroChoregraphyWidget = listMenu.DualTextWidget:extend() +menu.EnnemyChoregraphyWidget = listMenu.DualTextWidget:extend() + +-- ShowBackground +function menu.HeroChoregraphyWidget:new(scene, charName, skillData) + menu.HeroChoregraphyWidget.super.new(self, scene, charName, skillData.name, "") + self.character = charName + self.skillData = skillData +end + +function menu.HeroChoregraphyWidget:action() + self.scene:playHeroChoregraphy(self.character, self.skillData) + self.scene.menusystem:deactivate() +end + +-- ShowBackground +function menu.EnnemyChoregraphyWidget:new(scene, category, charName, skillData) + menu.EnnemyChoregraphyWidget.super.new(self, scene, charName, skillData.name, "") + self.category = category + self.character = charName + self.skillData = skillData +end + +function menu.EnnemyChoregraphyWidget:action() + self.scene:playEnnemyChoregraphy(self.category, self.character, self.skillData) + self.scene.menusystem:deactivate() +end + + +return menu diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/action.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/action.lua new file mode 100644 index 0000000..19e785e --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/action.lua @@ -0,0 +1,18 @@ +local ActionParent = require "scenes.battlesystem.fighters.character.actions.parent" +local ActionMock = ActionParent:extend() + +function ActionMock:new(fighter, data) + ActionMock.super.new(self, fighter) + self.data = data +end + +function ActionMock:needTarget() + return (self.data.targetNumber == 1), self.data.targetEnnemies +end + +function ActionMock:startAction() + core.debug:print("cbs/action", "Starting mock action") + self:loadChoregraphyFromSkill(self.data) +end + +return ActionMock diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/fighter.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/fighter.lua new file mode 100644 index 0000000..b40e5c5 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/fighter.lua @@ -0,0 +1,50 @@ +local FighterMock = Object:extend() + +local ActionMock = require "scenes.menus.debugmenus.choregraphy.mocks.action" +local TargetMock = require "scenes.menus.debugmenus.choregraphy.mocks.target" +local TurnSystemMock = require "scenes.menus.debugmenus.choregraphy.mocks.turnSystem" + +function FighterMock:new(scene) + self.scene = scene + self.action = nil + self.actor = nil + self.turnSystem = TurnSystemMock() +end + +function FighterMock:update(dt) + if (self.action ~= nil) then + self.action:update(dt) + end +end + +function FighterMock:playHeroChoregraphy(character, data) + self.name = character + self.abstract = game.characters.list[character] + self.actor = self.scene.world.obj.Hero(self.scene.world, 11, 3, self, 1) + self.action = ActionMock(self, data) + self.action:setTarget(TargetMock(self.scene)) + self.action:start() +end + +function FighterMock:playEnnemyChoregraphy(category, ennemy, data) + self.name = ennemy + self.category = category + self.abstract = game.ennemies:getEnnemyData(category, ennemy) + self.actor = self.scene.world.obj.Ennemy(self.scene.world, 11, 3, self, 1) + self.action = ActionMock(self, data) + self.action:setTarget(TargetMock(self.scene)) + self.action:start() +end + +function FighterMock:finishAction() + self.action.target.actor:destroy() + self.actor:destroy() + self.action = nil + self.scene.menusystem:activate() +end + +function FighterMock:drawHUD() + +end + +return FighterMock diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/target.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/target.lua new file mode 100644 index 0000000..ac1b448 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/target.lua @@ -0,0 +1,8 @@ +local TargetMock = Object:extend() + +function TargetMock:new(scene) + self.scene = scene + self.actor = self.scene.world.obj.Battler(self.scene.world, 2, 3, 0, self) +end + +return TargetMock diff --git a/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/turnSystem.lua b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/turnSystem.lua new file mode 100644 index 0000000..dc93f38 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/debugmenus/choregraphy/mocks/turnSystem.lua @@ -0,0 +1,11 @@ +local TurnSystemMock = Object:extend() + +function TurnSystemMock:new() + +end + +function TurnSystemMock:applyDeath() + +end + +return TurnSystemMock diff --git a/sonic-bluestreak.love/scenes/menus/init.lua b/sonic-bluestreak.love/scenes/menus/init.lua new file mode 100644 index 0000000..941170a --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/init.lua @@ -0,0 +1,10 @@ +return { + title = require "scenes.menus.titlescreen", + main = require "scenes.menus.mainmenu", + debug = { + battleBack = require "scenes.menus.debugmenus.battleBack", + choregraphy = require "scenes.menus.debugmenus.choregraphy", + animation = require "scenes.menus.debugmenus.animation", + }, + options = require "scenes.menus.options" +} diff --git a/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/character.lua b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/character.lua new file mode 100644 index 0000000..5a100b4 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/character.lua @@ -0,0 +1,31 @@ +local Parent = require "scenes.menus.mainmenu.infopanel.parent" +local CharacterPanel = Parent:extend() + +function CharacterPanel:new(character) + CharacterPanel.super.new(self) + self.character = character +end + +function CharacterPanel:drawContent(x, y) + local stats = self.character.stats + + local debugString = "# DEBUG - " .. self.character.name .. "(" .. "Lvl " .. self.character.level .. ")" .. "\n" + local debugString = debugString .. "EXP: " .. self.character.exp .. " / " .. self.character.exp_next .. "\n" + local debugString = debugString .. "HP: " .. self.character.hp .. " / " .. stats:get(stats.HPMAX) .. "\n" + local debugString = debugString .. "PP: " .. self.character.pp .. " / " .. stats:get(stats.PPMAX) .. "\n" + local debugString = debugString .. self:addToDebugString(stats, stats.ATTACK) + local debugString = debugString .. " " .. self:addToDebugString(stats, stats.DEFENSE) + local debugString = debugString .. " " .. self:addToDebugString(stats, stats.SPEED) .. "\n" + local debugString = debugString .. self:addToDebugString(stats, stats.POWER) + local debugString = debugString .. " " .. self:addToDebugString(stats, stats.MIND) + local debugString = debugString .. " " .. self:addToDebugString(stats, stats.TECHNIC) .. "\n" + + love.graphics.print(debugString, x, y) +end + +function CharacterPanel:addToDebugString(stats, statname) + local stats = stats + return stats.CONST.SIMPLENAME[statname] .. ": " .. stats:get(statname) +end + +return CharacterPanel diff --git a/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/gamedata.lua b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/gamedata.lua new file mode 100644 index 0000000..3bffb16 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/gamedata.lua @@ -0,0 +1,17 @@ +local Parent = require "scenes.menus.mainmenu.infopanel.parent" +local GamePanel = Parent:extend() + +function GamePanel:new() + GamePanel.super.new(self) +end + +function GamePanel:drawContent(x, y) + local debugString = "# DEBUG - Save data" .. "\n" + debugString = debugString .. "Current slot: " .. game.slot .. " / " .. game.slotNumber .. "\n" + debugString = debugString .. "Rings: " .. game.loot.rings .. "\n" + debugString = debugString .. "Gametime: " .. game:getTimeString() .. "\n" + + love.graphics.print(debugString, x, y) +end + +return GamePanel diff --git a/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/init.lua b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/init.lua new file mode 100644 index 0000000..1b1fe46 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/init.lua @@ -0,0 +1,7 @@ +local folder = "scenes.menus.mainmenu.infopanel." + +return { + Gamedata = require(folder .. "gamedata"), + Character = require(folder .. "character"), + Team = require(folder .. "team"), +} diff --git a/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/parent.lua b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/parent.lua new file mode 100644 index 0000000..cce8114 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/parent.lua @@ -0,0 +1,19 @@ +local ParentPanel = Object:extend() +local gui = require "game.modules.gui" + +function ParentPanel:new() + self.panelBackground = gui.newTextBox("assets/gui/dialogbox.png", 128+32, 128) +end + +function ParentPanel:draw(x, y, w, h) + if (core.debug.active) then + love.graphics.draw(self.panelBackground, x, y) + self:drawContent(x+8, y+8) + end +end + +function ParentPanel:drawContent(x, y) + +end + +return ParentPanel diff --git a/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/team.lua b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/team.lua new file mode 100644 index 0000000..8f85b61 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/mainmenu/infopanel/team.lua @@ -0,0 +1,22 @@ +local Parent = require "scenes.menus.mainmenu.infopanel.parent" +local TeamPanel = Parent:extend() + +function TeamPanel:new() + TeamPanel.super.new(self) +end + +function TeamPanel:drawContent(x, y) + local debugString = "# DEBUG - Team" .. "\n" + for i,name in ipairs(game.characters.team) do + local char = game.characters.list[name] + debugString = debugString .. "- " .. char.name + if (game.characters.active == i) then + debugString = debugString .. " (Active) " + end + debugString = debugString .. "\n" + end + + love.graphics.print(debugString, x, y) +end + +return TeamPanel diff --git a/sonic-bluestreak.love/scenes/menus/mainmenu/init.lua b/sonic-bluestreak.love/scenes/menus/mainmenu/init.lua new file mode 100644 index 0000000..5ab75d2 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/mainmenu/init.lua @@ -0,0 +1,15 @@ +local Scene = require "game.scenes" + +local DebugMenu = Scene:extend() + +local MenuBack = require "game.modules.gui.menuback" + +local MainMenu = require "scenes.menus.mainmenu.menu" + +function DebugMenu:new() + DebugMenu.super.new(self, true, true) + MainMenu() + MenuBack() +end + +return DebugMenu; diff --git a/sonic-bluestreak.love/scenes/menus/mainmenu/menu.lua b/sonic-bluestreak.love/scenes/menus/mainmenu/menu.lua new file mode 100644 index 0000000..2f5b1f8 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/mainmenu/menu.lua @@ -0,0 +1,48 @@ +local Parent = require "game.modules.gui.fancymenu" +local MainMenu = Parent:extend() + +local defTransitions = require "birb.modules.transitions" +local radTransitions = require "game.modules.transitions" + +local MENU_X, MENU_Y = 24, 48 +local MENU_W = 424/3 +local MENU_ITEM_NUMBER = 8 + +function MainMenu:new() + MainMenu.super.new(self, "mainmenu", MENU_X, MENU_Y, MENU_W, MENU_ITEM_NUMBER, false) + self:addItem("Launch game", "left", function() self:launchGame() end) + self:addItem("Options", "left", function() self:launchOptions() end) + self:addItem("Battle Level", "left", function() self:battle() end) + self:addItem("Shadow Shoot Level", "left", function() self:shadowShot() end) + self:addItem("Return to title", "left", function() self:returnToTitle() end, "back") + self:setCancelWidget() + self:addItem("Exit game", "left", function() self:exitGame() end) + self:getFocus() +end + +function MainMenu:launchGame() + core.screen:startTransition(defTransitions.circle, defTransitions.default, function() scenes.overworld() end, 424/2, 240/2) + core.scenemanager.currentScene:hideOverlay() +end + +function MainMenu:launchOptions() + core.screen:startTransition(defTransitions.default, defTransitions.default, function() scenes.menus.options() end, 424/2, 240/2) +end + +function MainMenu:returnToTitle() + core.screen:startTransition(defTransitions.circle, radTransitions.borders, function() scenes.menus.title(true) end, 424/2, 240/2) +end + +function MainMenu:battle() + core.screen:startTransition(defTransitions.default, defTransitions.default, function() scenes.test("ebeach") end, 424/2, 240/2) +end + +function MainMenu:shadowShot() + core.screen:startTransition(defTransitions.circle, radTransitions.borders, function() scenes.test2() end, 424/2, 240/2) +end + +function MainMenu:exitGame() + love.event.quit("000") +end + +return MainMenu diff --git a/sonic-bluestreak.love/scenes/menus/options/init.lua b/sonic-bluestreak.love/scenes/menus/options/init.lua new file mode 100644 index 0000000..7e4e7b4 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/options/init.lua @@ -0,0 +1,34 @@ +local Scene = require "game.scenes" +local OptionsMenu = Scene:extend() + +local OptionMenu = require "scenes.menus.options.menu" + +local gui = require "game.modules.gui" +local MenuBack = require "game.modules.gui.menuback" + +function OptionsMenu:new() + OptionsMenu.super.new(self, true, true) + + self.keyDetector = {} + self.keyDetector.widget = nil + + OptionMenu() + MenuBack() +end + +function OptionsMenu:changeKey(widget) + self.keyDetector.widget = widget +end + +function OptionsMenu:keypressed( key ) + if (self.keyDetector.widget ~= nil) then + self.assets:playSFX("mSelect") + self.gui.elements["optionMenu"].isVisible = true + self.gui:delayFocus("optionMenu", 0.1) + self.keyDetector.widget:receiveKey( key ) + self.keyDetector.isActive = false + self.keyDetector.widget = nil + end +end + +return OptionsMenu diff --git a/sonic-bluestreak.love/scenes/menus/options/menu.lua b/sonic-bluestreak.love/scenes/menus/options/menu.lua new file mode 100644 index 0000000..52614d1 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/options/menu.lua @@ -0,0 +1,216 @@ +local Parent = require "game.modules.gui.boxedmenu" +local MainMenu = Parent:extend() + +local TextMenuWidget = require "birb.modules.gui.textmenu.widgets.basic" +local ResolutionWidget = TextMenuWidget:extend() +local SwitchWidget = TextMenuWidget:extend() +local AudioWidget = TextMenuWidget:extend() +local DifficultyWidget = TextMenuWidget:extend() +local KeysWidget = TextMenuWidget:extend() + +local defTransitions = require "birb.modules.transitions" +local ConfirmDialog = require "game.modules.confirmdialog" + +local MENU_Y = 48 +local MENU_W = 424 / 1.5 +local MENU_ITEM_NUMBER = 8 + +function MainMenu:new() + local screenw, screenh = core.screen:getDimensions() + MainMenu.super.new(self, "optionMenu", screenw/2, MENU_Y, MENU_W, MENU_ITEM_NUMBER, true) + self.ox = MENU_W/2 + self:addVideoMenu() + self:addAudioMenu() + self:addDifficultyMenu() + self:addInputMenu() + self:switch("main") + self:addItem("Delete save", "left", function() self:deleteSave() end, "select", nil, {1, 0.3, 0.3}) + self:addItem("Exit", "left", function() self:exit() end, "back") + self:setCancelWidget() + self:getFocus() +end + +function MainMenu:addVideoMenu() + self:addSubmenu("video", "Videos", "main", true) + ResolutionWidget() + SwitchWidget("fullscreen", "Fullscreen") + SwitchWidget("border", "Borders") + SwitchWidget("vsync", "Vsync") +end + +function MainMenu:addAudioMenu() + self:addSubmenu("audio", "Audio", "main", true) + AudioWidget("music", "Music") + AudioWidget("sfx", "SFX") +end + +function MainMenu:addDifficultyMenu() + self:addSubmenu("difficulty", "Difficulty", "main", true) + DifficultyWidget("hazardMakesKo", "Hazards can make KO") + DifficultyWidget("playerKoChar", "Play KO characters on maps") + DifficultyWidget("easierBattles", "Easier battles") + DifficultyWidget("checkPointRegen", "Checkpoints heal you") + DifficultyWidget("levelUpHeal", "Gaining a level heal") + DifficultyWidget("allDamage", "Hazards damage everybody") +end + +function MainMenu:addInputMenu() + self:addSubmenu("input", "Input", "main", true) + local keyList = require "datas.keys" + for j, key in ipairs(keyList) do + KeysWidget(key) + end +end + +function MainMenu:exit() + core.screen:startTransition(defTransitions.default, defTransitions.default, + function() scenes.menus.main() end, 0, 0) +end + +function MainMenu:deleteSave() + local confirm = ConfirmDialog(core.scenemanager.currentScene, + "Do you want to delete your save ? \nYou won't be able to recover your data.", + function() + core.scenemanager:setStoredScene("mainmenu") + game:deleteCurrentSave() + core.screen:startTransition(defTransitions.default, defTransitions.circle, + function() scenes.menus.title(true) end, + 424/2, 240/2) + end) + confirm:setCancelChoice(2) +end + + +-- WIDGETS + +function ResolutionWidget:new() + ResolutionWidget.super.new(self, "optionMenu", core.lang:translate("options", "resolution"), "left") + self:addLabel(self:getSecondLabel(), "right") +end + +function ResolutionWidget:getSecondLabel() + return "x" .. core.options.data.video.resolution +end + +function ResolutionWidget:action() + core.options.data.video.resolution = ((core.options.data.video.resolution) % 3) + 1 + self:replaceLabel(2, self:getSecondLabel()) + core.screen:applySettings() + self:invalidateCanvas() + core.options:write() +end + +-- SWITCH + +function SwitchWidget:new(keyname, label) + self.keyname = keyname + SwitchWidget.super.new(self, "optionMenu", label, "left") + self:addLabel(self:getSecondLabel(), "right") +end + +function SwitchWidget:modifyKey() + core.options.data.video[self.keyname] = (core.options.data.video[self.keyname] == false) + core.screen:applySettings() +end + +function SwitchWidget:getKey() + return core.options.data.video[self.keyname] +end + +function SwitchWidget:getSecondLabel() + return core.lang:translate("commons", utils.math.either(self:getKey(), "true", "false")) +end + +function SwitchWidget:action() + self:modifyKey() + self:replaceLabel(2, self:getSecondLabel()) + core.options:write() + self:invalidateCanvas() +end + +-- AUDIO + +function AudioWidget:new(audiotype, label) + self.audiotype = audiotype + SwitchWidget.super.new(self, "optionMenu", label, "left") + self:addLabel(self:getSecondLabel(), "right") + self.order = 0 +end + +function AudioWidget:getSecondLabel() + return utils.math.numberToString(self:getVolume(), 3) .. "%" +end + +function AudioWidget:getVolume() + return core.options.data.audio[self.audiotype] +end + +function AudioWidget:setVolume(vol) + core.options.data.audio[self.audiotype] = utils.math.either(vol >= 0, vol, 100) +end + +function AudioWidget:action() + local value = self:getVolume() + self:setVolume(value - 20) + self:replaceLabel(2, self:getSecondLabel()) + self:invalidateCanvas() + --self.scene.assets.music:setVolume(core.options.data.audio.music / 100) + core.options:write() +end + +-- DIFFICULTY + +function DifficultyWidget:new(keyname, label) + self.keyname = keyname + SwitchWidget.super.new(self, "optionMenu", label, "left") + self:addLabel(self:getSecondLabel(), "right") +end + +function DifficultyWidget:modifyKey() + game.difficulty:toggle(self.keyname) +end + +function DifficultyWidget:getKey() + return game.difficulty:get(self.keyname) +end + +function DifficultyWidget:getSecondLabel() + return core.lang:translate("commons", utils.math.either(self:getKey(), "true", "false")) +end + +function DifficultyWidget:action() + self:modifyKey() + self:replaceLabel(2, self:getSecondLabel()) + game:write() + self:invalidateCanvas() +end + +-- KEYS + +function KeysWidget:new(key) + self.source = 1 + self.key = key + + SwitchWidget.super.new(self, "optionMenu", self.key, "left") + self:addLabel(self:getSecondLabel(), "right") + self.type = "navigate" +end + +function KeysWidget:getSecondLabel() + return core.input.data[self.source].keys[self.key] +end + +function KeysWidget:action() + self.menu:playSFX("navigate") + self.scene:changeKey(self) + self.menu.isVisible = false + self.menu:looseFocus() +end + +function KeysWidget:receiveKey( key ) + core.options:setInputKey(self.source, self.key, key) + self:replaceLabel(2, self:getSecondLabel()) + self:invalidateCanvas() +end + +return MainMenu diff --git a/sonic-bluestreak.love/scenes/menus/titlescreen/init.lua b/sonic-bluestreak.love/scenes/menus/titlescreen/init.lua new file mode 100644 index 0000000..ff6954b --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/titlescreen/init.lua @@ -0,0 +1,44 @@ +-- scenes/test :: a basic test scene + +--[[ + Copyright © 2019 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local Scene = require "game.scenes" +local Title = Scene:extend() +local TitleScreen = require "scenes.menus.titlescreen.screen" + +function Title:new(fromMenu) + Title.super.new(self, true, true) + + self.assets:addImage("logo", "assets/artworks/logo.png") + self.assets:addTileset("charicons", "assets/sprites/characters/charicons") + + TitleScreen(fromMenu) +end + +function Title:startPressed() + self.assets:playSFX("mSelect") + self.menusystem:setSoundFromSceneAssets("mBeep") + self.gui.focusedElement = nil + self.gui:playScreenTransform("titleScreen", "showMenu") +end + +return Title diff --git a/sonic-bluestreak.love/scenes/menus/titlescreen/menu.lua b/sonic-bluestreak.love/scenes/menus/titlescreen/menu.lua new file mode 100644 index 0000000..5fe321b --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/titlescreen/menu.lua @@ -0,0 +1,73 @@ +local RadianceMenu = require "birb.modules.gui.menus.listbox" +local RadianceWidget = require "birb.modules.gui.menus.widgets.base" +local SaveMenu = RadianceMenu:extend() +local SaveWidget = RadianceWidget:extend() + +local gui = require "game.modules.gui" + +local defTransitions = require "birb.modules.transitions" +local radTransitions = require "game.modules.transitions" + +local HPADDING = 68 +local VPADDING = 28 + +function SaveMenu:new() + local w, h = 424 - (HPADDING * 2), 240 - (VPADDING * 2) + + SaveMenu.super.new(self, "save", 424/2, 240/2, w, h, 3) + self.ox = w/2 + self.oy = h/2 + self.sx = 0.8 + self.sy = 0.8 + self.opacity = 0 + local metadata = game:getMetadata() + for i, save in ipairs(metadata) do + SaveWidget(self.scene, i, save) + end + self.textBox = gui.newTextBox("assets/gui/dialogbox.png", w - 8, (h / 3)) + self.isVisible = true +end + +function SaveMenu:cancelAction() + self:playSFX("back") + self.gui:playScreenTransform("titleScreen", "hideMenu") + self:looseFocus() +end + +function SaveWidget:new(scene, saveid, savedata) + SaveWidget.super.new(self, "save") + self.saveid = saveid + self.savedata = savedata + self.emeralds = gui.getEmeraldsTexture(self.savedata.emeralds) +end + +function SaveWidget:drawCanvas() + local basex, basey = 4, 2 + love.graphics.draw(self.menu.textBox, basex, basey) + if (self.savedata.exist) then + local str = "Save " .. self.saveid + str = str .. "(" .. utils.math.numberToString(self.savedata.completion,3) .. "%)" + str = str .. " - " .. utils.time.toString(self.savedata.gametime) + str = str .. "\n" + str = str .. self.savedata.location .. "\n" + str = str .. "Rings: " .. self.savedata.rings + self.assets.fonts["small"]:draw(str, basex + 8, basey + 4) + + for i, charName in ipairs(self.savedata.team) do + local data = core.datas:get("characters", charName) + local x = 18*(#self.savedata.team - i + 1) + 4 + basex + self.scene.assets.tileset["charicons"]:drawTile(data.icon,self.width - x, basey + 4) + end + + love.graphics.draw(self.emeralds, basex + 168, basey + 21) + else + self.assets.fonts["small"]:draw("New save", basex + 8, basey + 4) + end +end + +function SaveWidget:action() + game:read(self.saveid) + core.screen:startTransition(radTransitions.borders, defTransitions.circle, function() scenes.menus.main() end, 424/2, 240/2) +end + +return SaveMenu diff --git a/sonic-bluestreak.love/scenes/menus/titlescreen/pressStart.lua b/sonic-bluestreak.love/scenes/menus/titlescreen/pressStart.lua new file mode 100644 index 0000000..532b21c --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/titlescreen/pressStart.lua @@ -0,0 +1,30 @@ +local TextElement = require "birb.modules.gui.elements.text" +local PressStart = TextElement:extend() + +function PressStart:new(isVisible) + PressStart.super.new(self, "pressStart", "SA2font", "PRESS START", 424/2, 240/1.33, "center") + self.isVisible = isVisible or false + self.showPressStartTimer = 0 +end + +function PressStart:update(dt) + self.showPressStartTimer = self.showPressStartTimer - dt + if self.showPressStartTimer < 0 then + self.showPressStart = (self.showPressStart == false) + self.showPressStartTimer = 0.5 + end +end + +function PressStart:draw() + if (self.showPressStart) then + PressStart.super.draw(self) + end +end + +function PressStart:keypressed(key) + if (key == "start") then + self.scene:startPressed() + end +end + +return PressStart \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/menus/titlescreen/screen.lua b/sonic-bluestreak.love/scenes/menus/titlescreen/screen.lua new file mode 100644 index 0000000..0f587c9 --- /dev/null +++ b/sonic-bluestreak.love/scenes/menus/titlescreen/screen.lua @@ -0,0 +1,59 @@ +local Screen = require "birb.modules.gui.screen" +local TitleScreen = Screen:extend() + +local AssetElement = require "birb.modules.gui.elements.assets" +local TextureElement = require "birb.modules.gui.elements.drawable" +local PressStart = require "scenes.menus.titlescreen.pressStart" +local ColorElement = require "birb.modules.gui.elements.color" + +local Menu = require "scenes.menus.titlescreen.menu" + +local either = utils.math.either + +local show = { + {"fade", "tween", 0.3, 0.4, {opacity = 0}, "outExpo"}, + {"logo", "movement", 0.5, 0.6, 424/2, 80, "inOutQuart"}, + {"flash", "tween", 1.1, 0.03, {opacity = 1}, "inQuart"}, + {"flash", "tween", 1.25, 0.2, {opacity = 0}, "outExpo"}, + --{"pressStart", "switch", 1.2, {"isVisible"}}, + --{"pressStart", "delayFocus", 1.2}, + } +local showMenu = { + {"save", "tween", 0, 0.25, {sx = 1, sy = 1, opacity = 1}, "inExpo"}, + {"save", "delayFocus", 0.25}, +} +local hideMenu = { + {"save", "tween", 0, 0.25, {sx = 0.8, sy = 0.8, opacity = 0}, "outExpo"}, + {"pressStart", "delayFocus", 0.25}, +} + +function TitleScreen:new(fromMenu) + self.fromMenu = (fromMenu == true) + TitleScreen.super.new(self, "titleScreen") + self:addTransform("show", show) + self:addTransform("showMenu", showMenu) + self:addTransform("hideMenu", hideMenu) + if (not self.fromMenu) then + self:show() + else + self.isVisible = true + end +end + +function TitleScreen:createElements() + local background = love.graphics.newImage("datas/gamedata/maps/sti/stuff/tilescreen.png") + local o = either(self.fromMenu, 0, 1) + local y = either(self.fromMenu, 80, -190) + local d = either(self.fromMenu, 0, 1.2) + return { + {TextureElement("background", background, 0, 0, 0, 1, 1, 0, 0, 1), 0, 200}, + {ColorElement("fade", 0, 0, 0, o), 0, 5}, + {AssetElement("logo", "images", "logo", 424/2, y, 0, 1, 1, "center", "center", 1, 0), 0, 4}, + {ColorElement("flash", 1, 1, 1, 0), 0, 1}, + {PressStart(self.fromMenu), d, 10, true}, + {Menu(self), 0, 4}, + } +end + + +return TitleScreen \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/encounter.lua b/sonic-bluestreak.love/scenes/overworld/actors/encounter.lua new file mode 100644 index 0000000..53aa5c3 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/encounter.lua @@ -0,0 +1,36 @@ +local Gizmo = require "scenes.overworld.actors.gizmo" +local Encounter = Gizmo:extend() + +local overrides = { + ["isSolid"] = false, + ["charset"] = "item1", + ["charId"] = 2, + ["destroy"] = "none", + ["needButton"] = false, + ["isTurning"] = true, +} + +function Encounter:new(world, x, y) + Encounter.super.new(self, world, x, y, 16, 16, overrides) +end + +function Encounter:action() + core.scenemanager:storeCurrentScene("afterBattle") + local ox, oy = self.world.cameras:getViewCoordinate(1) + game.cbs:startBattle("test", "testBattle", self.x - ox, self.y - oy) + self.world.encounter = self + self.scene.isPlaying = "" +end + +function Encounter:drawCharset(charset, charId) + local x, y = utils.math.floorCoord(self.x, self.y) + y = y - 2 + + love.graphics.setColor(1,1,1,0.5) + self.assets.images["shadow"]:draw(x, y + 11) + utils.graphics.resetColor() + + self.assets.sprites["encounter"]:draw(x - 1, y + 10) + end + +return Encounter \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/gfx.lua b/sonic-bluestreak.love/scenes/overworld/actors/gfx.lua new file mode 100644 index 0000000..f2f611e --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/gfx.lua @@ -0,0 +1,22 @@ +local cwd = (...):gsub('%.gfx$', '') .. "." +local Parent = require(cwd .. "parent") +local GFX = Parent:extend() + +function GFX:new(world, x, y, spritename) + local width, height = world.scene.assets.sprites[spritename]:getDimensions() + + GFX.super.new(self, world, "gfx", x - (width/2), y - (height/2), width, height) + self:setSprite(spritename, true) +end + +function GFX:animationEnded(animation) + core.debug:print("gfx2D", 'Current animation "' .. animation .. '" have ended, destroying gfx') + self:destroy() +end + +function GFX:draw() + local x, y = math.floor(self.x), math.floor(self.y) + self:drawSprite(x, y) +end + +return GFX \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/gizmo.lua b/sonic-bluestreak.love/scenes/overworld/actors/gizmo.lua new file mode 100644 index 0000000..3bffe35 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/gizmo.lua @@ -0,0 +1,86 @@ +local Parent = require "scenes.overworld.actors.parent" +local Gizmo = Parent:extend() + +local defaultEvent = { + {"simpleMessage", "", "ERROR 000 NO EVENT"}, +} + +function Gizmo:new(world, x, y, w, h, overrides) + local w = w or 16; + local h = h or 16; + Gizmo.super.new(self, world, "gizmo", x, y, w, h, false) + self.overrides = overrides + self.drawDebugBox = false + self.event = defaultEvent + self.interactionName = "Talk" +end + +function Gizmo:getUniqueId() + return "gizmo" .. ":" .. self.mapname .. ":" .. self.x .. ":" .. self.y +end + +function Gizmo:setProperties(properties) + self:setDefaultProperties() + self:replaceProperties(properties) + if (self.overrides ~= nil) then + self:replaceProperties(self.overrides) + end + self:applyProperties() +end + +function Gizmo:applyProperties() + -- Apply properties to the internal item system + self.isSolid = self.properties.isSolid + self.mainHitbox.isSolid = self.properties.isSolid + if (self.isSolid) then + self:addHitbox("btnInput", "btnInput", {-1, -1, self.w + 2, self.h + 2}, false) + end + self.needButton = self.properties.needButton + self.charId = self.properties.charId or 1 + self.charset = self.properties.charset or nil + self.charDir = self.properties.charDir or "down" + self.cantTurn = self.properties.cantTurn or self.cantTurn + self.isTurning = (self.properties.isTurning == true) + if (self.properties.event ~= nil) then + local data = require("datas.gamedata.events." .. self.properties.event) + self.event = data.actions + end + self.uniqueId = self:getUniqueId() + if (game.destroyedGizmo[self.uniqueId] == true) then + self:destroy() + end + self.interactionName = self.properties.interactionName or self.interactionName +end + +function Gizmo:setDefaultProperties() + local default = require "game.utils.gizmo.properties" + self.properties = {} + for key, value in pairs(default) do + self.properties[key] = value + end +end + +function Gizmo:replaceProperties(properties) + for key, _ in pairs(properties) do + if (properties[key] ~= nil) then + self.properties[key] = properties[key] + end + end +end + +function Gizmo:doAction() + self:action() + if (self.properties.destroy == "forever") then + game.destroyedGizmo[self.uniqueId] = true + self:destroy() + end + if (self.properties.destroy == "temp") then + self:destroy() + end +end + +function Gizmo:action() + self.scene.events:startEvent(self, self.event) +end + +return Gizmo; \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/init.lua b/sonic-bluestreak.love/scenes/overworld/actors/init.lua new file mode 100644 index 0000000..4637d79 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/init.lua @@ -0,0 +1,29 @@ +local Obj = {} + +-- On charge toutes les différentes types d'acteurs +local cwd = (...):gsub('%.init$', '') .. "." +Obj.Player = require(cwd .. "player") +Obj.Gizmo = require(cwd .. "gizmo") +Obj.Teleporter = require(cwd .. "teleport") +Obj.PNJ = require(cwd .. "pnj") +Obj.Encounter = require(cwd .. "encounter") +Obj.GFX = require(cwd .. "gfx") + +Obj.loot = require(cwd .. "loot") + +Obj.index = {} +Obj.index["player"] = Obj.Player +Obj.index["gizmo"] = Obj.Gizmo +Obj.index["teleporter"] = Obj.Teleporter +Obj.index["pnj"] = Obj.PNJ +Obj.index["encounter"] = Obj.Encounter + +Obj.index["ring"] = Obj.loot.Ring +Obj.index["itembox"] = Obj.loot.ItemBox +Obj.index["ringbox"] = Obj.loot.RingBox + +Obj.collisions = {} +Obj.collisions["wall"] = require(cwd .. "wall") +Obj.collisions["gizmo-collision"] = Obj.Gizmo + +return Obj diff --git a/sonic-bluestreak.love/scenes/overworld/actors/loot/init.lua b/sonic-bluestreak.love/scenes/overworld/actors/loot/init.lua new file mode 100644 index 0000000..9afbb91 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/loot/init.lua @@ -0,0 +1,7 @@ +local Loot = {} + +Loot.Ring = require "scenes.overworld.actors.loot.ring" +Loot.RingBox = require "scenes.overworld.actors.loot.ringbox" +Loot.ItemBox = require "scenes.overworld.actors.loot.itembox" + +return Loot \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/loot/itembox.lua b/sonic-bluestreak.love/scenes/overworld/actors/loot/itembox.lua new file mode 100644 index 0000000..23dd48d --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/loot/itembox.lua @@ -0,0 +1,28 @@ +local Gizmo = require "scenes.overworld.actors.gizmo" +local ItemBox = Gizmo:extend() + +local overrides = { + ["isSolid"] = true, + ["charset"] = "item1", + ["charId"] = 1, + ["charDir"] = "right", + ["destroy"] = "forever", + ["needButton"] = true, + ["interactionName"] = "Take", +} + +function ItemBox:new(world, x, y) + ItemBox.super.new(self, world, x, y, 16, 16, overrides) +end + +function ItemBox:applyProperties() + ItemBox.super.applyProperties(self) + self.event = { + {"getItems", "", self.properties.category, self.properties.item, self.properties.number}, + {"playSFX", "", "pop"}, + {"simpleMessage", "", "You got " .. self.properties.number .. " " .. self.properties.item}, + {"showGFX", "", self.x + 16, self.y + 14, "smallsmoke"} + } +end + +return ItemBox \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/loot/ring.lua b/sonic-bluestreak.love/scenes/overworld/actors/loot/ring.lua new file mode 100644 index 0000000..af4472f --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/loot/ring.lua @@ -0,0 +1,23 @@ +local Gizmo = require "scenes.overworld.actors.gizmo" +local Ring = Gizmo:extend() + +local overrides = { + ["isSolid"] = false, + ["charset"] = "item1", + ["charId"] = 2, + ["destroy"] = "temp", + ["needButton"] = false, + ["isTurning"] = true, +} + +function Ring:new(world, x, y) + Ring.super.new(self, world, x, y, 16, 16, overrides) +end + +function Ring:action() + self.assets.sfx["ring"]:play() + game.loot.rings = game.loot.rings + 1 + self.world.obj.GFX(self.world, self.x + 16, self.y + 8, "sparkles") +end + +return Ring \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/loot/ringbox.lua b/sonic-bluestreak.love/scenes/overworld/actors/loot/ringbox.lua new file mode 100644 index 0000000..94c5369 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/loot/ringbox.lua @@ -0,0 +1,28 @@ +local Gizmo = require "scenes.overworld.actors.gizmo" +local RingBox = Gizmo:extend() + +local overrides = { + ["isSolid"] = true, + ["charset"] = "item1", + ["charId"] = 1, + ["charDir"] = "down", + ["destroy"] = "forever", + ["needButton"] = true, + ["interactionName"] = "Take", +} + +function RingBox:new(world, x, y) + RingBox.super.new(self, world, x, y, 16, 16, overrides) +end + +function RingBox:applyProperties() + RingBox.super.applyProperties(self) + self.event = { + {"getRings", "", self.properties.number}, + {"playSFX", "", "pop"}, + {"simpleMessage", "", "You got " .. self.properties.number .. " rings"}, + {"showGFX", "", self.x + 16, self.y + 14, "smallsmoke"} + } +end + +return RingBox \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/parent.lua b/sonic-bluestreak.love/scenes/overworld/actors/parent.lua new file mode 100644 index 0000000..2c1f4ef --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/parent.lua @@ -0,0 +1,90 @@ +local Base = require "birb.modules.world.actors.actor2D" +local Parent = Base:extend() + +function Parent:new(world, type, x, y, w, h, isSolid) + self.scene = world.scene + self.z = 0 + Parent.super.new(self, world, type, x, y, w, h, isSolid) + self:initCharset() + self.drawDebugBox = false +end + +function Parent:update(dt) + self.depth = -self.y + Parent.super.update(self, dt) + self.depth = -self.y +end + +function Parent:isMoving() + return ((math.abs(self.ysp) > 0.01) or (math.abs(self.xsp) > 0.01)) +end + +-- Charset / Draw functions +-- Handle the charset of an object + +function Parent:initCharset() + self.charsetManager = self.world.scene.charsetManager + self.charset = nil + self.charDir = "down" + self.cantWalk = false + self.cantTurn = false + self.isTurning = false + self.isFast = false + self.largeAnim = false + self.alwaysWalk = false + self.scissorSprite = false + self.groundHeight = 0 +end + +function Parent:setCharset(charset, charId, cantWalk) + self.charset = charset + self.charId = charId + self.cantWalk = (cantWalk == true) +end + +function Parent:drawCharset(charset, charId) + local x, y = utils.math.floorCoord(self.x, self.y) + y = y - 2 + local z = math.floor(self.z) + + love.graphics.setColor(1,1,1,0.5) + if (self.groundHeight == 0) then + self.assets.images["shadow"]:draw(x + 1, y + 11) + end + utils.graphics.resetColor() + + if (self.scissorSprite) then + local _, camy = self.world.cameras:getViewCoordinate(1) + local viewy = math.floor((self.y + self.h - self.groundHeight) - camy) + love.graphics.setScissor(0, 0, 424, viewy) + end + + if (self.largeAnim) then + self.charsetManager:drawLargeAnim(self.charset, self.charId, self.charDir, x, y - z, self.isFast) + else + if (not self.isTurning) then + if ((self:isMoving() and (not self.cantWalk)) or self.alwaysWalk) then + self.charsetManager:drawMoving(self.charset, self.charId, self.charDir, x, y - z, self.isFast) + else + self.charsetManager:drawStanding(self.charset, self.charId, self.charDir, x, y - z) + end + else + self.charsetManager:drawTurning(self.charset, self.charId, x, y - z, self.isFast) + end + end + + if (self.scissorSprite) then + love.graphics.setScissor() + end +end + +function Parent:draw() + if (self.drawDebugBox) then + love.graphics.rectangle("line", math.floor(self.x), math.floor(self.y), self.w, self.h) + end + if (self.charset ~= nil) then + self:drawCharset() + end +end + +return Parent diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/actions.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/actions.lua new file mode 100644 index 0000000..3aa3dfe --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/actions.lua @@ -0,0 +1,234 @@ +local PlayerActions = Object:extend() + +local BASE_SPEED = 120 +local RUN_FACTOR = 2.5 +local JMP_STRENGHT = 2.5 + +local ACTIONS = {} +ACTIONS["speedster"] = {"run"} +ACTIONS["technic"] = {"fly"} +ACTIONS["power"] = {"punch"} + +function PlayerActions:initActions() + self.currentAction = "idle" + self.canJump = true + self.canAct = true + self.speedFactor = 1 + self.forceAction = nil + self.dashJustStarted = false +end + +function PlayerActions:canDoAction(action) + local classCanDoAction = utils.table.contain(ACTIONS[self:getCurrentCharType()], action) + local playerCanDoAction = utils.table.contain(game.actions, action) + return (classCanDoAction and playerCanDoAction) +end + +function PlayerActions:act() + if (self.forceAction ~= nil) then + self:forcedAction() + else + self:actionMove() + self:actionJump() + self:actionSwitch() + self:actionRun() + self:actionPunch() + end +end + +function PlayerActions:forcedAction() + local charSpeed = BASE_SPEED * self.speedFactor + + if (self.forceAction == "slide") then + if (self.xsp ~= 0 or self.ysp ~= 0) then + if (self.currentAction == "run") then + charSpeed = charSpeed * RUN_FACTOR + end + self.xsp, self.ysp = utils.math.lengthdir(charSpeed, math.rad(self.charsetManager.angle[self.charDir])) + self.xsp = -self.xsp + else + self:actionMove() + end + end +end + +function PlayerActions:actionMove() + local charSpeed = BASE_SPEED * self.speedFactor + + if (self.currentAction == "punch") then + return + end + + if (self.currentAction == "jumpdash" or self.currentAction == "run") then + local xsp, ysp = self:getDash() + if (utils.table.contain({"up", "down"}, self.charDir)) then + if self.keys["left"].isDown then + xsp = -charSpeed + end + if self.keys["right"].isDown then + xsp = charSpeed + end + if (self.ysp == 0) then + if (self.currentAction == "jumpdash") then + self.currentAction = "jump" + else + self.currentAction = "idle" + end + elseif (self.dashJustStarted) then + self.dashJustStarted = false + self.assets.sfx["dash"]:play() + end + else + if self.keys["up"].isDown then + ysp = -charSpeed + end + if self.keys["down"].isDown then + ysp = charSpeed + end + if (self.xsp == 0) then + if (self.currentAction == "jumpdash") then + self.currentAction = "jump" + else + self.currentAction = "idle" + end + elseif (self.dashJustStarted) then + self.dashJustStarted = false + self.assets.sfx["dash"]:play() + end + end + self.xsp, self.ysp = xsp, ysp + else + if self.keys["up"].isDown then + self.ysp = -charSpeed + self.charDir = "up" + end + if self.keys["down"].isDown then + self.ysp = charSpeed + self.charDir = "down" + end + if self.keys["left"].isDown then + self.xsp = -charSpeed + self.charDir = "left" + end + if self.keys["right"].isDown then + self.xsp = charSpeed + self.charDir = "right" + end + end +end + +function PlayerActions:getCharspeed() + return BASE_SPEED * self.speedFactor +end + +function PlayerActions:getDash() + local xsp, ysp = utils.math.lengthdir(self:getCharspeed() * RUN_FACTOR, math.rad(self.charsetManager.angle[self.charDir])) + return -xsp, ysp +end + +function PlayerActions:actionJump() + if self.keys["B"].isPressed then + if (self.onGround and self.canJump) then + self:goUpward(JMP_STRENGHT) + self.assets.sfx["jump"]:play() + if (self.currentAction == "run") then + self.currentAction = "jumpdash" + else + self.currentAction = "jump" + end + elseif (self.currentAction == "jump" and self:canDoAction("fly")) then + self.currentAction = "fly" + self.grav = 0 + self.zsp = 0 + self.tweens:newTimer(0.75, "endFly") + self.assets.sfx["fly"]:play() + end + end + + if self.keys["B"].isReleased then + self:endFly() + end +end + +function PlayerActions:endFly() + if (self.currentAction == "fly") then + self:goUpward(0) + self.currentAction = "idle" + end +end + +function PlayerActions:actionSwitch() + if self.keys["select"].isPressed and (self.currentAction == "idle") then + self:switchActiveCharacter() + end +end + +function PlayerActions:actionRun() + if self.keys["C"].isPressed then + if (self:canDoAction("run") and self.speedFactor > 0) then + self.dashJustStarted = true + if (utils.table.contain({"run", "idle"}, self.currentAction)) then + self.currentAction = "run" + elseif (utils.table.contain({"jumpdash", "jump"}, self.currentAction)) then + self.currentAction = "jumpdash" + end + self.xsp, self.ysp = self:getDash() + end + elseif (not self.keys["C"].isDown) then + if (self.currentAction == "run") then + self.currentAction = "idle" + elseif (self.currentAction == "jumpdash") then + self.currentAction = "jump" + end + end +end + +function PlayerActions:actionPunch() + if self.keys["C"].isPressed then + if (self:canDoAction("punch")) then + self.assets.sfx["hit"]:play() + self.xsp, self.ysp = utils.math.lengthdir(BASE_SPEED * RUN_FACTOR, math.rad(self.charsetManager.angle[self.charDir])) + self.xsp = -self.xsp + self.currentAction = "punch" + self.tweens:newTimer(0.15, "endPunch") + self.assets.sprites["punch"]:changeAnimation("default", true) + end + end +end + +function PlayerActions:endPunch() + if (self.currentAction == "punch") then + self.currentAction = "idle" + end +end + +function PlayerActions:endJump() + if (self.currentAction == "jump") then + self.currentAction = "idle" + elseif (self.currentAction == "jumpdash") then + self.currentAction = "run" + end +end + +function PlayerActions:drawActionEffect() + if (((self.currentAction == "run") or (self.currentAction == "jumpdash")) and (self.xsp ~= 0 or self.ysp ~= 0)) then + local dx, dy = utils.math.lengthdir(20, math.rad(self.charsetManager.angle[self.charDir])) + if (self.charDir == "down") then + dy = 8 + elseif (self.charDir == "left" or self.charDir == "right") then + dy = -8 + end + local x, y = self.x + 8 - dx, self.y + 8 - self.z + dy + self.assets.sprites["dash"]:draw(x, y, math.rad(self.charsetManager.angle[self.charDir])) + end + if (self.currentAction == "punch") then + local dx, dy = utils.math.lengthdir(20, math.rad(self.charsetManager.angle[self.charDir])) + if (self.charDir == "down") then + dy = 8 + end + local x, y = self.x + 8 - dx, self.y + 8 - self.z + dy + self.assets.sprites["punch"]:draw(x, y, math.rad(self.charsetManager.angle[self.charDir])) + end +end + +return PlayerActions diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/charset.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/charset.lua new file mode 100644 index 0000000..9469c19 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/charset.lua @@ -0,0 +1,53 @@ +local PlayerCharset = Object:extend() + +local ACTIONS_LARGEANIM = {"jump", "jumpdash"} +local ACTIONS_ISFAST = {"jump", "fly", "run", "jumpdash"} +local ACTIONS_ALWAYSWALK = {"fly"} +local ACTIONS_DONTWALK = {"slide"} + +function PlayerCharset:initPlayerCharset() + self.scissorSprite = true + self:updateCurrentCharset() +end + +function PlayerCharset:updateCurrentCharset() + self:setCharset(self:getCharset(), self.active.data.charId) + self.isFast = self:getIsFast() + self.largeAnim = self:getLargeAnim() + self.alwaysWalk = self:getAlwaysWalk() + self.cantWalk = self:getDontWalk() +end + +function PlayerCharset:getCharset() + local charset = self.active.data.charset + if (self.currentAction == "jump" or self.currentAction == "jumpdash") then + charset = charset .. "-jump" + elseif (self.currentAction == "fly") then + charset = charset .. "-flight" + elseif (self.currentAction == "punch") then + charset = charset .. "-jump" + end + return charset +end + +function PlayerCharset:getLargeAnim() + return utils.table.contain(ACTIONS_LARGEANIM, self.currentAction) +end + +function PlayerCharset:getIsFast() + return utils.table.contain(ACTIONS_ISFAST, self.currentAction) +end + +function PlayerCharset:getAlwaysWalk() + return utils.table.contain(ACTIONS_ALWAYSWALK, self.currentAction) +end + +function PlayerCharset:getDontWalk() + if (self.forceAction ~= nil) then + return utils.table.contain(ACTIONS_DONTWALK, self.forceAction) + else + return utils.table.contain(ACTIONS_DONTWALK, self.currentAction) + end +end + +return PlayerCharset diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/health.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/health.lua new file mode 100644 index 0000000..96bb584 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/health.lua @@ -0,0 +1,37 @@ +local PlayerHealth = Object:extend() + +local ComplexHPBar = require "game.modules.gui.complexhpbar" + +local HPBAR_SIZE = 80 + +function PlayerHealth:initHealth() + self.hpbar = ComplexHPBar(HPBAR_SIZE) + self.hpbar:setColorForeground(248/255, 160/255, 0, 1) + self.hpbar:setColorBackground(112/255, 0, 0) + self.fallDamage = 0 + self.fallSound = "" +end + +function PlayerHealth:drawHealth(x, y) + for i, name in ipairs(game.characters.team) do + local yy = y + (i * 17) + local character = game.characters.list[name] + self.scene.assets.fonts["hudnbrs_small"]:set() + self.hpbar:drawWithLabels(x + 18, yy, character.hp, character.stats:get(character.stats.HPMAX)) + self.assets.tileset["charicons"]:drawTile(character.data.icon, x, yy - 3) + end +end + +function PlayerHealth:takeDamage(damage) + local damage = damage or 10 + damage = damage / 100 + if (game.difficulty:get("allDamage")) then + for _, name in ipairs(game.characters.team) do + game.characters:sendDamageFromMap(name, damage) + end + else + game.characters:sendDamageFromMap(game.characters.team[game.characters.active], damage) + end +end + +return PlayerHealth \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/init.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/init.lua new file mode 100644 index 0000000..b9c17af --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/init.lua @@ -0,0 +1,142 @@ +local Parent = require "scenes.overworld.actors.parent" +local Player = Parent:extend() + +local TweenManager = require "birb.classes.time" +local Team = require "scenes.overworld.actors.player.team" +local Interactions = require "scenes.overworld.actors.player.interactions" +local Actions = require "scenes.overworld.actors.player.actions" +local Charset = require "scenes.overworld.actors.player.charset" +local Map = require "scenes.overworld.actors.player.map" +local Health = require "scenes.overworld.actors.player.health" + +Player:implement(Team) +Player:implement(Interactions) +Player:implement(Actions) +Player:implement(Charset) +Player:implement(Map) +Player:implement(Health) + +local FRICTION = 480 * 3 +local GRAV = 10 +local DEFAULT_GROUND_LEVEL = 0 +local DEFAULT_GROUND_HEIGHT = 0 +local RESPAWN_LIMIT = -32 + +function Player:new(world, x, y, id) + Player.super.new(self, world, "player", x, y, 16, 16, true) + self.groundLevel = DEFAULT_GROUND_LEVEL + self.groundHeight = DEFAULT_GROUND_HEIGHT + self.z = self.groundLevel + self.grav = GRAV + self.tweens = TweenManager(self) + + self.onGround = true + self.xfrc, self.yfrc = FRICTION, FRICTION + + self:initTeam() + self:initInteractions() + self:initActions() + self:initPlayerCharset() + self:initMap() + self:initHealth() +end + +function Player:updateStart(dt) + self.interactionName = "" + self.tweens:update(dt) + self:updateTerrain() + self:updateActiveCharacter() + + self:act() + + self.world:getTileTypeAtPoint(self.x, self.y) + + self:updateInteraction() + self:updateCurrentCharset() + self:updateCurrentMap() + self:updateOutsideMap() +end + +-- PHYSICS FUNCTIONS +-- Some functions to hook up the physic system +function Player:goUpward(zsp) + self.zsp = zsp + self.grav = GRAV + self.onGround = false +end + +function Player:applyGravity(dt) + local grav = self.grav * -1 + self.zsp = self.zsp + (grav * dt) + + if utils.math.sign(self.zsp) == utils.math.sign(grav) then + self:checkGround() + end +end + +function Player:checkGround() + if (self.z + self.zsp <= self.groundLevel) then + self.onGround = true + self.z = self.groundLevel + self.zsp = 0 + self:endJump() + if (self.z <= RESPAWN_LIMIT) then + self.x = self.lastPos.x + self.y = self.lastPos.y + self:takeDamage(self.fallDamage) + if (not utils.string.isEmpty(self.fallSound)) then + self.assets:playSFX(self.fallSound) + end + end + end +end + +function Player:autoMove(dt) + Player.super.autoMove(self, dt) + self.z = self.z + self.zsp +end + +-- RESPONSES +-- Reponse to timer and collisions + +function Player:collisionResponse(col) + local hitbox = col.other + local other = col.other.owner + if (not other.isDestroyed) then + if (hitbox.type == "gizmo") then + self:collideWithGizmo(other) + elseif (hitbox.type == "btnInput" and other.needButton) then + self:talkToGizmo(other) + end + end +end + +function Player:timerResponse(response) + if (response == "changeCharacter") then + self:endCharacterSwitchAnimation() + elseif (response == "endFly") then + self:endFly() + elseif (response == "endPunch") then + self:endPunch() + end +end + +function Player:drawHUD(id) + self:drawHealth((424 - self.scene:getEmblemsPosition()) - 48, 168) + self:drawEmblems(self.scene:getEmblemsPosition(), 24) + if (not utils.string.isEmpty(self.interactionName)) then + local w = self.assets.fonts["small"]:getWidth(self.interactionName) + 16 + love.graphics.setColor(0,0,0,0.5) + local x, y = 424 - w + 4, 240 - 24 + love.graphics.rectangle("fill", x - w/2, y + 1, w, 15, 8, 8) + utils.graphics.resetColor() + self.assets.fonts["small"]:draw(self.interactionName, x, y, -1, "center") + end +end + +function Player:draw() + Player.super.draw(self) + self:drawActionEffect() +end + +return Player diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/interactions.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/interactions.lua new file mode 100644 index 0000000..6fa9ccd --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/interactions.lua @@ -0,0 +1,177 @@ +local PlayerInteractions = Object:extend() + +local terrainData = require "datas.gamedata.maps.terrains" + +local MIN_X = 2 +local MAX_X = 14 +local MIN_Y = 9 +local MAX_Y = 15 + +local TERRAIN_CHECKER = { + {x = MIN_X, y = MIN_Y}, + {x = MIN_X, y = MAX_Y}, + {x = MAX_X, y = MIN_Y}, + {x = MAX_X, y = MAX_Y}, +} + +function PlayerInteractions:initInteractions() + self.lastCollision = -1 + self.haveCollided = false + self.terrain = {} + self.terrain.name = "" + self.terrain.data = {} + self.terrain.new = false + self.lastPos = {} + self.lastPos.x = self.x + self.lastPos.y = self.y + self.interactionName = "" +end + +function PlayerInteractions:updateInteraction() + if (self.haveCollided == false) then + self.lastCollision = nil + end + self.haveCollided = false +end + +function PlayerInteractions:collideWithGizmo(other) + if (other.needButton) then + self.interactionName = other.interactionName + if (self.keys["A"].isPressed) then + other:doAction() + self.haveCollided = true + self.lastCollision = other.creationID + self.interactionName = "" + end + else + if (self.lastCollision ~= other.creationID) then + other:doAction() + end + self.haveCollided = true + self.lastCollision = other.creationID + end +end + +function PlayerInteractions:talkToGizmo(other) + if (self:faceRightDirection(other)) then + self.interactionName = other.interactionName + if (self.keys["A"].isPressed) then + other:doAction() + self.haveCollided = true + self.lastCollision = other.creationID + self.interactionName = "" + end + end +end + +function PlayerInteractions:faceRightDirection(other) + if (self.charDir == "up") then + return (self.y >= other.y + other.h) + end + if (self.charDir == "down") then + return (self.y + self.h <= other.y) + end + if (self.charDir == "left") then + return (self.x >= other.x + other.w) + end + if (self.charDir == "right") then + return (self.x + self.w <= other.x) + end +end + +function PlayerInteractions:updateTerrain() + local newTerrain = self:getCurrentTerrain() + if (newTerrain ~= self.terrain.name) then + self.terrain.new = true + end + self.terrain.name = newTerrain + self:updateTerrainData() + if (newTerrain == "non-solid") then + self:updateLastPosition() + end +end + +function PlayerInteractions:updateLastPosition() + local canUpdate = true + for _, coord in ipairs(TERRAIN_CHECKER) do + local xx, yy = coord.x, coord.y + if (xx == MIN_X) then xx=0 else xx=16 end + if (yy == MIN_Y) then yy=0 else yy=16 end + local newTerrain = self.world:getTileTypeAtPoint(self.x + xx, self.y + yy) + if (newTerrain ~= "non-solid") then + canUpdate = false + end + end + if (canUpdate and self.onGround) then + self.lastPos = {} + self.lastPos.x = self.x + self.lastPos.y = self.y + end +end + +function PlayerInteractions:updateTerrainData() + local dataPack = terrainData.list[self.terrain.name] + local newData = terrainData.list["non-solid"][1] + + if (dataPack == nil) then + dataPack = terrainData.list["non-solid"] + end + + for id, data in ipairs(dataPack) do + local useThisData = true + if (data.mustHaveAction ~= nil and not self:canDoAction(data.mustHaveAction)) then + useThisData = false + end + if (data.mustDoAction ~= nil and data.mustDoAction ~= self.currentAction) then + useThisData = false + end + + if (useThisData) then + newData = data + end + end + + self:setTerrainData(newData) +end + +function PlayerInteractions:setTerrainData(data) + self.groundLevel = data.level or 0 + self.groundHeight = data.height or 0 + if (self.onGround) then + self.speedFactor = data.speedFactor or 1 + self.canJump = data.canJump ~= false + self.canAct = data.canAct ~= false + self.forceAction = data.forceAction + end + if (self.terrain.new and (self.z < 0)) then + self.terrain.new = false + if (not utils.string.isEmpty(data.sound)) then + self.assets:playSFX(data.sound) + end + end + self.fallDamage = data.fallDamage or 0 + self.fallSound = data.fallSound or "" + self.terrain.data = data +end + +function PlayerInteractions:getCurrentTerrain() + local terrain = "" + local highpriority = terrainData.highpriority + for _, coord in ipairs(TERRAIN_CHECKER) do + local newTerrain = self.world:getTileTypeAtPoint(self.x + coord.x, self.y + coord.y) + if (utils.table.contain(highpriority, newTerrain)) then + terrain = newTerrain + elseif (newTerrain == "non-solid") then + if (not utils.table.contain(highpriority, terrain)) then + terrain = newTerrain + end + else + if (not (utils.table.contain(highpriority, terrain) or terrain == "non-solid")) then + terrain = newTerrain + end + end + end + return terrain +end + +return PlayerInteractions diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/map.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/map.lua new file mode 100644 index 0000000..3ab97d0 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/map.lua @@ -0,0 +1,28 @@ +local PlayerMap = Object:extend() +local defTransitions = require "birb.modules.transitions" + +function PlayerMap:initMap() + self.previousMap = 0 +end + +function PlayerMap:updateCurrentMap() + local currentMap = self.world.map:getMapAtPoint(self.x, self.y) + if (currentMap ~= nil) then + if (self.previousMap ~= currentMap.id) then + self.previousMap = currentMap.id + self.scene:updateCurrentMap(currentMap) + end + end +end + +function PlayerMap:updateOutsideMap() + if ((self.x > self.world.map.w + 8) or (self.x < -8) or (self.y > self.world.map.h + 16) or (self.y < -8)) + and (self.world.map.data.exitTo ~= nil) then + local arguments = self.world.map.data.exitTo + core.screen:startTransition(defTransitions.default, defTransitions.default, + function() self.world:teleport(arguments.area, arguments.x, arguments.y, arguments.charDir) end, + 0, 0) + end +end + +return PlayerMap \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/punch.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/punch.lua new file mode 100644 index 0000000..c17b6ad --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/punch.lua @@ -0,0 +1,17 @@ +local Base = require "birb.modules.world.actors.actor2D" +local Punch = Base:extend() + +function Punch:new(world, x, y, dir) + Punch.super.new(self, world, "wall", x, y, 8, 8, false) +end + +function Punch:update(dt) + self.depth = -self.y + Punch.super.update(self, dt) +end + +function Punch:draw() + +end + +return Punch \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/player/team.lua b/sonic-bluestreak.love/scenes/overworld/actors/player/team.lua new file mode 100644 index 0000000..ab44f0f --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/player/team.lua @@ -0,0 +1,64 @@ +local Team = Object:extend() + +local Emblem = require "game.modules.gui.emblem" + +function Team:initTeam() + self.active = game.characters:getActiveCharacterData() + + self.emblems = {} + for i, name in ipairs(game.characters.team) do + game.characters:loadSprite(self.assets, name) + self.emblems[i] = Emblem(game.characters.list[name], self.scene) + end + + self.activeVisible = game.characters.active + self.canChangeActive = true +end + +function Team:updateActiveCharacter() + local everybodyIsKo = true + for id, name in ipairs(game.characters.team) do + if (game.characters.list[name].hp > 0) then + everybodyIsKo = false + break; + end + end + if (everybodyIsKo) then + self.scene:gameover() + else + if ((self.active.hp == 0) and not game.difficulty:get("playerKoChar")) then + self:switchActiveCharacter() + end + end +end + +function Team:getCurrentCharType() + return self.active.data.class +end + +function Team:switchActiveCharacter() + if (self.canChangeActive) then + local count = game.characters:setActiveCharacter() + self.active = game.characters:getActiveCharacterData() + self.canChangeActive = false + self.tweens:newTimer(0.3, "changeCharacter") + self.tweens:newTween(0, 0.3, {activeVisible = self.activeVisible + count}, "inQuad") + end +end + +function Team:endCharacterSwitchAnimation() + self.canChangeActive = true + self.activeVisible = game.characters.active + self:updateCurrentCharset() +end + +function Team:drawEmblems(x, y) + for i,emblem in ipairs(self.emblems) do + local angle = ((i-self.activeVisible) * (360/#self.emblems)) - 90 + local rad = math.rad(angle) + local emblemX, emblemY = utils.math.lengthdir(18, rad) + emblem:draw(x + emblemX, y + emblemY) + end + end + +return Team \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/pnj.lua b/sonic-bluestreak.love/scenes/overworld/actors/pnj.lua new file mode 100644 index 0000000..a158f28 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/pnj.lua @@ -0,0 +1,50 @@ +local Gizmo = require "scenes.overworld.actors.gizmo" +local PNJ = Gizmo:extend() + +local overrides = { + ["isSolid"] = true, + ["destroy"] = "nope", + ["needButton"] = true, + ["interactionName"] = "Talk", +} + +function PNJ:new(world, x, y) + PNJ.super.new(self, world, x, y, 16, 16, overrides) +end + +function PNJ:applyProperties() + PNJ.super.applyProperties(self) + self.messages = {} + for i = 1, 9, 1 do + local message = self.properties["message" .. i] + if (message ~= nil) then + table.insert(self.messages, message) + end + end + self.messageType = self.properties.messageType or "random" + self.currentMessage = 1 +end + +function PNJ:setMessage() + local message = self.messages[1] + if (self.messageType == "random") then + message = self.messages[math.random(#self.messages)] + elseif (self.messageType == "list") then + message = self.messages[self.currentMessage] + self.currentMessage = self.currentMessage + 1 + if (self.currentMessage > #self.messages) then + self.currentMessage = 1 + end + end + self.event = { + {"dialogBox", "", message, self.properties.title, ""}, + } +end + +function PNJ:action() + self:setMessage() + PNJ.super.action(self) +end + + +return PNJ \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/teleport.lua b/sonic-bluestreak.love/scenes/overworld/actors/teleport.lua new file mode 100644 index 0000000..bbd826c --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/teleport.lua @@ -0,0 +1,17 @@ +local Gizmo = require "scenes.overworld.actors.gizmo" +local Teleporter = Gizmo:extend() + +function Teleporter:new(world, x, y, w, h) + Teleporter.super.new(self, world, x, y, w, h, nil) + self.interactionName = "Enter" +end + +function Teleporter:applyProperties() + Teleporter.super.applyProperties(self) + local charDir = self.properties.charDir or "default" + self.event = { + {"teleport", "", self.properties.area, self.properties.x, self.properties.y, charDir}, + } +end + +return Teleporter \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/overworld/actors/wall.lua b/sonic-bluestreak.love/scenes/overworld/actors/wall.lua new file mode 100644 index 0000000..5c9342c --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/actors/wall.lua @@ -0,0 +1,14 @@ +local Base = require "birb.modules.world.actors.actor2D" +local Wall = Base:extend() + +function Wall:new(world, x, y, w, h) + Wall.super.new(self, world, "wall", x, y, w, h, true) + self:setDebugColor(0,0,0) +end + +function Wall:draw() + --self:drawHitbox() + --utils.graphics.resetColor( ) +end + +return Wall diff --git a/sonic-bluestreak.love/scenes/overworld/charsetmanager.lua b/sonic-bluestreak.love/scenes/overworld/charsetmanager.lua new file mode 100644 index 0000000..023bc8e --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/charsetmanager.lua @@ -0,0 +1,129 @@ +local Charset = Object:extend() + +local folder = "assets/sprites/charset/" +local animation = {1, 2, 3, 2} +local directionList = {"down", "right", "up", "left"} + +local angle = { + down = 270, + right = 180, + up = 90, + left = 0 +} + +local CHARWIDTH = 38 +local CHARHEIGHT = 48 +local FAST_BOOST = 2.5 + +local FRAME_STANDING = 2 + +function Charset:new(scene) + self.char = {} + self.list = {} + + for i=1, 2 do + for j=1, 4 do + local id = ((i-1)*4) + j + self.char[id] = self:addChar(i, j) + end + end + self.currentFrame = 0 + self.fastFrame = 0 + self.angle = angle +end + +function Charset:update(dt) + if (core.screen:isActive()) then + self.currentFrame = ((self.currentFrame + (dt*5)) % 4) + self.fastFrame = ((self.fastFrame + (dt*5*FAST_BOOST)) % 4) + end +end + +function Charset:addChar(ii, jj) + local charx, chary = (jj-1)*(CHARWIDTH*3), (ii-1)*(CHARHEIGHT*4) + local char = {} + for i=1, 4 do + local animatedDirection = {} + local running = {} + for j=1, 3 do + local x, y = charx + ((j-1)*CHARWIDTH), (chary + (i-1)*CHARHEIGHT) + --print(x, y) + running[j] = love.graphics.newQuad(x, y, CHARWIDTH, CHARHEIGHT, CHARWIDTH*12, CHARHEIGHT*8) + end + local direction = directionList[i] + char[direction] = running + end + return char +end + +function Charset:getTexture(charsetName) + if (self.list[charsetName] == nil) then + self:addTexture(charsetName) + end + return self.list[charsetName] +end + +function Charset:addTexture(charsetName) + self.list[charsetName] = love.graphics.newImage(folder .. charsetName .. ".png") +end + +-- FRAME FUNCTIONS +-- Easily get frame + +function Charset:getCurrentFrame(isFast) + local frame = self.currentFrame + if (isFast == true) then + frame = self.fastFrame + end + return math.min(math.floor(frame) + 1, 4) +end + +function Charset:getQuad(frame, charID, direction) + local char = self.char[charID] + local animatedDirection = char[direction] + local trueFrame = animation[frame] + return animatedDirection[trueFrame] +end + +-- DRAW FUNCTIONS +-- Draw the charset in various situations +function Charset:draw(charsetName, charID, direction, frame, x, y, isMirrored) + local drawable = self:getTexture(charsetName) + local quad = self:getQuad(frame, charID, direction) + local sx = 1 + if (isMirrored == true) then + sx = -1 + end + love.graphics.draw(drawable, quad, math.floor(x) + 8, math.floor(y), 0, sx, 1, 19, 32) +end + +function Charset:drawMoving(charsetName, charID, direction, x, y, isFast, isMirrored) + local frame = self:getCurrentFrame(isFast) + self:draw(charsetName, charID, direction, frame, x, y, isMirrored) +end + +function Charset:drawStanding(charsetName, charID, direction, x, y, isMirrored) + self:draw(charsetName, charID, direction, FRAME_STANDING, x, y, isMirrored) +end + +function Charset:drawLargeAnim(charsetName, charID, direction, x, y, isFast) + local frame = FRAME_STANDING + local isMirrored = false + for i, dir in ipairs(directionList) do + if (dir == direction) then + frame = animation[i] + end + end + if (direction == "left") then + isMirrored = true + end + self:drawTurning(charsetName, charID, x, y, isFast, frame, isMirrored) +end + +function Charset:drawTurning(charsetName, charID, x, y, isFast, frame, isMirrored) + local frame = frame or FRAME_STANDING + local dir = self:getCurrentFrame(isFast) + return self:draw(charsetName, charID, directionList[dir], frame, x, y, isMirrored) +end + +return Charset diff --git a/sonic-bluestreak.love/scenes/overworld/gui/hudelements/emblems.lua b/sonic-bluestreak.love/scenes/overworld/gui/hudelements/emblems.lua new file mode 100644 index 0000000..d125c3f --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/gui/hudelements/emblems.lua @@ -0,0 +1,14 @@ +local GuiElement = require "birb.modules.gui.elements.parent" +local TeamEmblems = GuiElement:extend() + +local POSITION = 368 + +function TeamEmblems:new() + TeamEmblems.super.new(self, "teamEmblems", 368, 0, 50, 50) +end + +function TeamEmblems:draw() + +end + +return TeamEmblems \ No newline at end of file diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/ennemy.lua b/sonic-bluestreak.love/scenes/overworld/gui/init.lua similarity index 100% rename from sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/ennemy.lua rename to sonic-bluestreak.love/scenes/overworld/gui/init.lua diff --git a/sonic-bluestreak.love/scenes/overworld/init.lua b/sonic-bluestreak.love/scenes/overworld/init.lua new file mode 100644 index 0000000..8337da9 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/init.lua @@ -0,0 +1,212 @@ +-- scenes/moveplayer :: a basic player movement example + +--[[ + Copyright © 2019 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local Scene = require "game.scenes" +local OverWorld = Scene:extend() + +local World = require "scenes.overworld.world" +local CharsetManager = require "scenes.overworld.charsetmanager" + +local screens = require "scenes.overworld.screens" + +local gui = require "game.modules.gui" +local TweenManager = require "birb.classes.time" + +local EventManager = require "game.events" +local MessageQueue = require "game.modules.messagequeue" + +function OverWorld:new(area, playerx, playery) + OverWorld.super.new(self) + self.charsetManager = CharsetManager(self) + self.assets:batchImport("assets.overworld") + + self.tweens = TweenManager(self) + self.screens = screens + + World(self, area, playerx, playery) + self.world:setPlayerNumber(1) + self.world:loadMap() + + self.currentScreen = nil + + self.backGroundOpacity = 0 + self.borderPosition = 0 + self.isPaused = false + self.canPause = true + + self.borders = gui.newBorder(424, 30, 8) + self.emblemPosition = 368 + self.ringBorder = -16 + self.tweens:newTween(0, 0.3, {ringBorder=16}, "inOutQuad") + self.timeBorder = -10 + + self.isPlaying = "" + + self.events = EventManager(self) +end + +function OverWorld:updateCurrentMap(map) + self:playMapMusic(map) + + self:showMessage(map.name) + game.mapName = map.name +end + +function OverWorld:playMapMusic(map) + local newMusic = map.music + if (newMusic ~= self.isPlaying) then + self.assets:setMusic("assets/music/" .. newMusic .. ".mp3") + self.assets:playMusic() + self.isPlaying = newMusic + end +end + +function OverWorld:startEvent() + self.world.isActive = false + self.canPause = false +end + +function OverWorld:endEvent() + self.world.isActive = true + self.canPause = true +end + +function OverWorld:registerScreen(screen) + if (self.currentScreen ~= nil) then + self.currentScreen:quit() + end + self.currentScreen = screen +end + +function OverWorld:update(dt) + local keys = self:getKeys(1) + self.tweens:update(dt) + self.events:update(dt) + + if (self.world.isActive) then + self.charsetManager:update(dt) + end + + if (self.currentScreen ~= nil) then + self.currentScreen:update(dt) + end + + if (keys["start"].isPressed and self.canPause) then + if (not self.isPaused) then + self.assets.sfx["mSelect"]:play() + self:pause() + else + self.assets.sfx["mBack"]:play() + self:unpause() + end + end +end + +function OverWorld:pause() + self.tweens:newTween(0,0.2, {backGroundOpacity=0.75}, "inQuad") + self.tweens:newTween(0,0.3, {borderPosition=30}, "inOutQuad") + self.tweens:newTween(0, 0.3, {emblemPosition=500}, "inOutQuad") + self.tweens:newTween(0, 0.3, {ringBorder=8}, "inOutQuad") + self.tweens:newTween(0, 0.3, {timeBorder=19}, "inOutQuad") + self.isPaused = true + self.world.isActive = false + screens.mainmenu.pause(self) +end + +function OverWorld:gameover() + self.tweens:newTween(0,0.2, {backGroundOpacity=0.75}, "inQuad") + self.tweens:newTween(0,0.3, {borderPosition=30}, "inOutQuad") + self.tweens:newTween(0, 0.3, {emblemPosition=500}, "inOutQuad") + self.tweens:newTween(0, 0.3, {ringBorder=-16}, "inOutQuad") + self.world.isActive = false + screens.gameover(self) +end + +function OverWorld:restored() + self.world:restoreActions() +end + +function OverWorld:timerResponse(timer) + if (timer == "unPause") then + self.isPaused = false + self.world.isActive = true + end +end + +function OverWorld:unpause() + self.tweens:newTween(0.1, 0.2, {backGroundOpacity=0}, "inQuad") + self.tweens:newTween(0, 0.3, {borderPosition=0}, "inOutQuad") + self.tweens:newTween(0, 0.3, {emblemPosition=368}, "inOutQuad") + self.tweens:newTween(0, 0.3, {ringBorder=16}, "inOutQuad") + self.tweens:newTween(0, 0.3, {timeBorder=-20}, "inOutQuad") + self.tweens:newTimer(0.2, "unPause") + + if (self.currentScreen ~= nil) then + self.currentScreen:quit() + end +end + +function OverWorld:quitScreen() + self.currentScreen = nil +end + +function OverWorld:getEmblemsPosition() + return self.emblemPosition +end + +function OverWorld:draw() + self.events:draw() + self:drawScreenBottomLayer() +end + +function OverWorld:drawOverTransition() + self:drawScreenTopLayer() +end + +function OverWorld:drawScreenBottomLayer() + love.graphics.setColor(0, 0, 0, self.backGroundOpacity) + love.graphics.rectangle("fill", 0, 0, 424, 240) + utils.graphics.resetColor() + + if (self.currentScreen ~= nil) then + self.currentScreen:drawBackground() + self.currentScreen:drawForeground() + end +end + +function OverWorld:drawScreenTopLayer() + love.graphics.draw(self.borders, 0, self.borderPosition, 0, 1, -1) + love.graphics.draw(self.borders, 424, 240 - self.borderPosition, 0, -1, 1) + + self.assets.images["guiRing"]:draw(self.ringBorder, self.ringBorder) + local ringString = utils.math.numberToString(game.loot.rings, 3) + self.assets.fonts["hudnbrs"]:print(ringString, self.ringBorder + 14, self.ringBorder + 1) + + self.assets.fonts["hudnbrs"]:print(game:getTimeString(), 424 - 16, 240 - self.timeBorder, "right") + + if (self.currentScreen ~= nil) then + self.currentScreen:drawOverEverything() + end +end + +return OverWorld diff --git a/sonic-bluestreak.love/scenes/overworld/map.lua b/sonic-bluestreak.love/scenes/overworld/map.lua new file mode 100644 index 0000000..670bd93 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/map.lua @@ -0,0 +1,189 @@ +local Parent = require "birb.modules.world.maps.parent" +local TiledMultiMap = Parent:extend() +local StiWrapper = require "birb.modules.world.maps.tiled.stiwrapper" + +local TiledMixins = require "birb.modules.world.maps.tiled.mixins" +TiledMultiMap:implement(TiledMixins) + +local mapFolder = "datas/gamedata/maps/sti/" +local areaFolder = "datas.gamedata.maps.area." + +function TiledMultiMap:new(world, area, playerx, playery) + self.wrappers = {} + self.data = require(areaFolder .. area) + self.w, self.h = 0, 0 + self.playerx, self.playery = playerx * 16, playery * 16 + self:loadMaps() + TiledMultiMap.super.new(self, world) + self.supportTileCollision = true + + self:setBackgroundColorFromTable(self.data.color) + self.mapname = self.data.areaName +end + +function TiledMultiMap:getMapName() + return self.data.areaName +end + +function TiledMultiMap:getDimensions() + return self.w, self.h +end + +function TiledMultiMap:loadObjects() + for i, wrapper in ipairs(self.wrappers) do + wrapper:loadObjects() + end + self:loadWalls() + self:loadPlayer() +end + +function TiledMultiMap:loadWalls() + if (self.data.exitTo == nil) then + self.world.obj.collisions["wall"](self.world, -16, -16, self.w, 16) + self.world.obj.collisions["wall"](self.world, -16, -16, 16, self.h) + self.world.obj.collisions["wall"](self.world, self.w, -16, 16, self.h) + self.world.obj.collisions["wall"](self.world, -16, self.h, self.w, 16) + end + +end + +function TiledMultiMap:loadPlayer() + self.world:addPlayer(self.playerx, self.playery, 0, 1) +end + +-- MAP HANDLING FUNCTIONS +-- Handle maps + +function TiledMultiMap:loadMaps() + for i, mapData in ipairs(self.data.maps) do + self:addMap(i, mapData) + end +end + +function TiledMultiMap:addMap(id, mapData) + core.debug:print("Loading map " .. mapData.name) + local mapFile = mapFolder .. mapData.folder .. "/" .. mapData.map .. ".lua" + local wrapper = StiWrapper(self, mapFile, mapData.x, mapData.y, false) + wrapper.id = id + wrapper.music = mapData.music + wrapper.name = mapData.name + table.insert(self.wrappers, wrapper) + self:pushDimensions(wrapper) +end + +function TiledMultiMap:pushDimensions(wrapper) + local x, y, w, h = wrapper:getRect() + self.w = math.max(self.w, x + w) + self.h = math.max(self.h, y + h) +end + +function TiledMultiMap:getMapAtPoint(x, y) + for i, wrapper in ipairs(self.wrappers) do + local recx, recy, recw, rech = wrapper:getRect() + local relx, rely = x - recx, y - recy + if (relx <= recw and relx >= 0) then + if (rely <= rech and rely >= 0) then + return wrapper + end + end + end +end + +function TiledMultiMap:getMapsInRect(x, y, w, h) + local listWrapper = {} + for i, wrapper in ipairs(self.wrappers) do + local recx, recy, recw, rech = wrapper:getRect() + local relx, rely = x - recx, y - recy + if (relx <= recw and relx + w >= 0) then + if (rely <= rech and rely + h >= 0) then + table.insert(listWrapper, wrapper) + end + end + end + return listWrapper +end + +-- TILE FUNCTIONS +-- Get tiles + +function TiledMultiMap:getTileTypeAtPoint(x, y) + local wrapper = self:getMapAtPoint(x, y) + if (wrapper ~= nil) then + return wrapper:getTileTypeAtPoint(x, y) + end +end + +function TiledMultiMap:haveTileTypeInRect(x, y, w, h, type) + local listWrapper = self:getMapsInRect(x, y, w, h) + for i, wrapper in ipairs(listWrapper) do + local haveTile = wrapper:haveTileTypeInRect(x, y, w, h, type) + if (haveTile) then + return true + end + return false + end +end + +-- UPDATE FUNCTION +-- Update or modify the map + +function TiledMultiMap:resize(w, h) + for i, wrapper in ipairs(self.wrappers) do + wrapper:resize(w, h) + end +end + +function TiledMultiMap:update(dt) + local x, y, w, h = self.world.cameras:getViewCoordinate(1) + local listWrapper = self:getMapsInRect(x, y, w, h) + for i, wrapper in ipairs(listWrapper) do + wrapper:update(dt) + end +end + +-- DRAW FUNCTIONS +-- Handle drawing the wrapper + + +function TiledMultiMap:drawUpperLayers() + local player = self.world.players[1].actor + local pos1AUpperLayer = self:haveUpperLayerAtCoord(player.x, player.y + 8) + local pos2AUpperLayer = self:haveUpperLayerAtCoord(player.x + 16, player.y + 8) + + local y = math.floor((player.y + 8)/16)*16 + if (pos1AUpperLayer or pos2AUpperLayer) then + y = math.floor((player.y - player.z)/16)*16 + end + local camx, camy = self.world.cameras:getViewCoordinate(1) + local viewy = math.floor(y - camy - 16) + love.graphics.setScissor(0, viewy, 424, 240) + self:drawUpperWrappers() + love.graphics.setScissor() +end + +function TiledMultiMap:haveUpperLayerAtCoord(x, y) + local wrapper = self:getMapAtPoint(x, y) + if (wrapper == nil) then + return false + end + return wrapper:haveUpperLayerAtCoord(x, y) +end + +function TiledMultiMap:drawUpperWrappers() + local x, y, w, h = self.world.cameras:getViewCoordinate(1) + local listWrapper = self:getMapsInRect(x, y, w, h) + for i, wrapper in ipairs(listWrapper) do + wrapper:drawUpperLayers() + end +end + +function TiledMultiMap:drawLowerLayers() + local x, y, w, h = self.world.cameras:getViewCoordinate(1) + local listWrapper = self:getMapsInRect(x, y, w, h) + for i, wrapper in ipairs(listWrapper) do + wrapper:drawLowerLayers() + end + self:drawUpperWrappers() +end + +return TiledMultiMap diff --git a/sonic-bluestreak.love/scenes/overworld/screens/gameover.lua b/sonic-bluestreak.love/scenes/overworld/screens/gameover.lua new file mode 100644 index 0000000..871db90 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/gameover.lua @@ -0,0 +1,89 @@ +local BaseScreen = require "scenes.overworld.screens.parent" +local GameOver = BaseScreen:extend() + +local TweenManager = require "birb.classes.time" + +local gui = require "game.modules.gui" + +local tw, th = 128, 32 + +local defTransitions = require "birb.modules.transitions" +local ConfirmDialog = require "game.modules.confirmdialog" + +function GameOver:new(scene) + GameOver.super.new(self, scene, "") + self.assets = scene.assets + self.turnSystem = scene.turns + + self:setVariables() + + self.continueBox = gui.newTextBox("assets/gui/dialogbox.png", tw, th) + + self.tweens = TweenManager(self) + self:prepareAnimation() +end + +function GameOver:setVariables() + -- Vignette Opacity + self.vignetteOpacity = 0 + + -- Battle FInished Label + self.labelOpacity = 0 + local width, height = core.screen:getDimensions() + self.labelX = width/2 + + -- Infobox + self.tbSize = 0.6 + self.tbOpacity = 0 +end + +function GameOver:prepareAnimation() + -- Label + self.tweens:newTween(0, 0.6, {labelOpacity=1}, 'inExpo') + self.tweens:newTween(0.9, 0.4, {labelX=4}, 'inExpo') + + self.tweens:newTimer(1.8, "continue") +end + +function GameOver:update(dt) + self.tweens:update(dt) +end + +function GameOver:draw() + local width, height = core.screen:getDimensions() + self:drawVignette(width, height) + self:drawLabel(width/2, 48, self.labelX, self.labelOpacity) +end + +function GameOver:timerResponse(timer) + if (timer == "continue") then + local confirm = ConfirmDialog(self.scene, "Do you want to return to title ? \nYou can also reload your latest save.", + function() self:returnToTitle() end, "Return to title", + function() self:loadLastSave() end, "Reload last save") + confirm.darken = false + end +end + +function GameOver:drawVignette(width, height) + love.graphics.setColor(0, 0, 0, self.vignetteOpacity) + + love.graphics.rectangle("fill", 0, 0, width, height) +end + +function GameOver:drawLabel(x, y, x2, opacity) + love.graphics.setColor(1, 1, 1, opacity) + + self.assets.fonts["SA2font"]:print("GAME", x - x2, y, "right") + self.assets.fonts["SA2font"]:print("OVER", x + x2, y, "left") +end + +function GameOver:returnToTitle() + core.screen:startTransition(defTransitions.default, defTransitions.circle, function() scenes.menus.title(true) end, 424/2, 240/2) +end + +function GameOver:loadLastSave() + self.scene.tweens:newTween(0, 0.3, {borderPosition=0}, "inOutQuad") + core.screen:startTransition(defTransitions.default, defTransitions.default, function() game:reload() scenes.overworld() end, 424/2, 240/2) +end + +return GameOver diff --git a/sonic-bluestreak.love/scenes/overworld/screens/init.lua b/sonic-bluestreak.love/scenes/overworld/screens/init.lua new file mode 100644 index 0000000..568e5e9 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/init.lua @@ -0,0 +1,4 @@ +return { + mainmenu = require "scenes.overworld.screens.mainmenu", + gameover = require "scenes.overworld.screens.gameover" +} diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/basicpage.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/basicpage.lua new file mode 100644 index 0000000..e639de3 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/basicpage.lua @@ -0,0 +1,69 @@ +local PageParent = require "scenes.overworld.screens.mainmenu.character.pageparent" +local BasicPage = PageParent:extend() + +local menu = require "game.modules.menus.fancy" +local gui = require "game.modules.gui" +local const = require "scenes.overworld.screens.mainmenu.const" + +local ComplexHPBar = require "game.modules.gui.complexhpbar" + +local HPBAR_SIZE = 80 + +function BasicPage:new(view, character) + self.view = view + self.character = game.characters.list[character] + + self.statBox = gui.newTextBox("assets/gui/dialogbox.png", const.CHARPAGESIZE, 48+8) + self.nameBox = gui.newTextBox("assets/gui/dialogbox.png", const.CHARPAGESIZE, 40) + + self.hpbar = ComplexHPBar(HPBAR_SIZE) + self.ppbar = ComplexHPBar(HPBAR_SIZE) + self.hpbar:setColorForeground(248/255, 160/255, 0, 1) + self.hpbar:setColorBackground(112/255, 0, 0) + self.ppbar:setColorForeground(0, 248/255, 248/255, 1) + self.ppbar:setColorBackground(0, 54/255, 229/255) + + BasicPage.super.new(self, view, character, {}) +end + +function BasicPage:draw() + self:drawIdentity(const.X, const.Y) + self:drawHPPP(const.X, const.Y + 48) + self:drawLevel(const.X, 100) + self:drawWeakStrong(const.X, 160) +end + +function BasicPage:drawIdentity(x, y) + local identityString = self.character.fullname .. "\n" + identityString = identityString .. "Class: " .. self.character.data.class + + love.graphics.draw(self.nameBox, x, y) + self.view.scene.assets.fonts["small"]:draw(identityString, x + 6, y + 4, -1, "left") +end + +function BasicPage:drawHPPP(x, y) + local stats = self.character.stats + self.view.scene.assets.fonts["hudnbrs_small"]:set() + self.hpbar:drawWithLabels(x, y - 4, self.character.hp, stats:get(stats.HPMAX)) + local xx = x + const.CHARPAGESIZE - HPBAR_SIZE - 7 + self.ppbar:drawWithLabels(xx, y - 4, self.character.pp, stats:get(stats.PPMAX)) +end + +function BasicPage:drawLevel(x, y) + local levelString = "Level: " .. self.character.level .. "\n" + local levelString = levelString .. "Current exp: " .. self.character.exp .. "\n" + local levelString = levelString .. "Next level: " .. self.character.exp_next + + love.graphics.draw(self.statBox, x, y) + self.view.scene.assets.fonts["small"]:draw(levelString, x + 6, y + 4, -1, "left") +end + +function BasicPage:drawWeakStrong(x, y) + local weakString = "Weak to: Nothing"--"Earth, Lightning" + local strongString = "Resist To: Nothing" + + love.graphics.draw(self.nameBox, x, y) + self.view.scene.assets.fonts["small"]:draw(weakString .. "\n" .. strongString, x + 6, y + 4, -1, "left") +end + +return BasicPage diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/init.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/init.lua new file mode 100644 index 0000000..e442e9d --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/init.lua @@ -0,0 +1,122 @@ +local ParentScreen = require "scenes.overworld.screens.parent" +local CharacterScreen = ParentScreen:extend() + +local menu = require "game.modules.menus.fancy" +local gui = require "game.modules.gui" +local const = require "scenes.overworld.screens.mainmenu.const" + +local BasicPage = require "scenes.overworld.screens.mainmenu.character.basicpage" +local StatPage = require "scenes.overworld.screens.mainmenu.character.statpage" +local SkillPage = require "scenes.overworld.screens.mainmenu.character.skillpage" +local pageList = {BasicPage, StatPage, SkillPage} + +local ReturnWidget = menu.BaseWidget:extend() + +function CharacterScreen:new(scene, character) + self.character = game.characters.list[character] + self.charName = character + + self.page = BasicPage(self, character) + self.pageIndex = 1 + + self.artwork = love.graphics.newImage("datas/gamedata/characters/" .. character .. "/artwork.png") + self.artworkOrigin = require("datas.gamedata.characters." .. character .. ".artwork") + CharacterScreen.super.new(self, scene, self.character.name) +end + +function CharacterScreen:update(dt) + local keys = self.scene:getKeys(1) + if (keys["left"].isPressed) then + self:setPage(self.pageIndex - 1) + self.scene.assets.sfx["mBeep"]:play() + end + if (keys["right"].isPressed) then + self:setPage(self.pageIndex + 1) + self.scene.assets.sfx["mBeep"]:play() + end +end + +function CharacterScreen:setPage(newPageIndex) + local newPageIndex = newPageIndex or 1 + if (newPageIndex > #pageList) then + newPageIndex = 1 + end + if (newPageIndex < 1) then + newPageIndex = #pageList + end + + self.pageIndex = newPageIndex + self.page = pageList[self.pageIndex](self, self.charName) + self.scene.menusystem:reset() + self:setMenu() +end + +function CharacterScreen:setMenu() + local itemNumber = self.page:getMenuSize() + local y = const.Y2 - (16*itemNumber) + 2 + menu.FancyMenu(self.scene, "menu", const.X2 - 128 - 14, y, 128, itemNumber, false) + self.page:getMenuWidgets() + ReturnWidget(self.scene, self.charName) + + local customMenu = self.page:getCustomMenus() + + self.scene.menusystem:switchMenu("menu") + self.scene.menusystem.menus["menu"]:getFocus() + self.scene.menusystem.menus["menu"]:setCancelWidget() + self.scene.menusystem.menus["menu"].isLocked = true + if (customMenu ~= nil) then + customMenu.isLocked = true + customMenu.isVisible = true + end + self.scene.menusystem:setSoundFromSceneAssets("mBeep") +end + +function CharacterScreen:draw() + if (self.page ~= nil) then + self.page:draw() + end + + for i = 1, #pageList, 1 do + local radius = 2 + if (i == self.pageIndex) then + radius = 3 + end + local x = (16*i) + 240 + 64 + local y = 17 + local outlineLight = 0.15 + love.graphics.circle("fill", x + 8, y + 8, radius, 8) + love.graphics.setColor(outlineLight, outlineLight, outlineLight, 1) + love.graphics.circle("line", x + 8, y + 8, radius, 8) + utils.graphics.resetColor() + end +end + +function CharacterScreen:drawBackground() + love.graphics.draw(self.artwork, self.artworkOrigin.x, self.artworkOrigin.y) +end + +function CharacterScreen:drawOverEverything() + if (self.page ~= nil) then + self.page:drawOverEverything() + end +end + +-- Widgets + +function ReturnWidget:new(scene, charName) + self.charName = charName + ReturnWidget.super.new(self, scene, "menu", "Back", "") +end + +function ReturnWidget:action() + for i, name in ipairs(game.characters.team) do + if (name == self.charName) then + self.widgetSelected = i + end + end + self.scene.assets:playSFX("mBack") + + self.scene.screens.mainmenu["pause"](self.scene, "character", self.widgetSelected) +end + +return CharacterScreen diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/pageparent.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/pageparent.lua new file mode 100644 index 0000000..b91b8cd --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/pageparent.lua @@ -0,0 +1,47 @@ +local PageParent = Object:extend() +local menu = require "game.modules.menus.fancy" +local Widget = menu.BaseWidget:extend() + +function PageParent:new(view, character, menu) + self.view = view + self.character = game.characters.list[character] + self.menu = menu or {} +end + +function PageParent:update(dt) +end + +function PageParent:getMenuSize() + return #self.menu + 1 +end + +function PageParent:getMenuWidgets() + for index, name in ipairs(self.menu) do + Widget(self, name, index) + end +end + +function PageParent:menuResponses(i) +end + +function PageParent:getCustomMenus() +end + +function PageParent:draw() +end + +function PageParent:drawOverEverything() +end + +function Widget:new(page, name, num) + self.num = num + self.page = page + Widget.super.new(self, self.page.view.scene, "menu", name, ">") +end + +function Widget:action() + self.page:menuResponses(self.num) + self.scene.assets.sfx["mBeep"]:play() +end + +return PageParent diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/skillpage.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/skillpage.lua new file mode 100644 index 0000000..db4681c --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/skillpage.lua @@ -0,0 +1,71 @@ +local PageParent = require "scenes.overworld.screens.mainmenu.character.pageparent" +local StatPage = PageParent:extend() + +local menu = require "game.modules.menus.list" +local const = require "scenes.overworld.screens.mainmenu.const" + +local SkillMenu = menu.ListMenu:extend() +local SkillWidget = menu.DualTextWidget:extend() +local PLAYER_MESSAGE = 240 - 24 + +function StatPage:new(view, character) + StatPage.super.new(self, view, character, {"See skill"}) + self.message = "" + self.showMessage = false +end + +function StatPage:getCustomMenus() + return SkillMenu(self, self.character) +end + +function StatPage:menuResponses(i) + if (#self.character.skills > 0) then + self.view.scene.menusystem:switchMenu("equip") + self.showMessage = true + end +end + +function StatPage:drawOverEverything() + if (not utils.string.isEmpty(self.message) and self.showMessage) then + love.graphics.setColor(0,0,0, 0.66) + love.graphics.rectangle("fill", 0, PLAYER_MESSAGE, 424, 16) + self.view.scene.assets.fonts["small"]:setColor(1,1,1, 1) + self.view.scene.assets.fonts["small"]:draw(self.message, 424/2, PLAYER_MESSAGE - 1, -1, "center") + self.view.scene.assets.fonts["small"]:setColor(1,1,1, 1) + utils.graphics.resetColor() + end +end + +function StatPage:setMessage(message) + self.message = message +end + +function StatPage:removeEquip(type) + self.character:removeEquip(type) +end + +function SkillMenu:new(page, character) + self.page = page + SkillMenu.super.new(self, page.view.scene, "equip", const.X, const.Y + 4, const.CHARPAGESIZE, 9, true, true) + for _, skill in ipairs(character.skills) do + SkillWidget(page, skill.name) + end +end + +function SkillMenu:cancelAction() + self.scene.menusystem.menus["menu"]:getFocus() + self.page.showMessage = false + self.scene.assets.sfx["mBack"]:play() +end + +function SkillWidget:new(page, skill) + self.page = page + self.skillData = core.datas:get("skills", skill) + SkillWidget.super.new(self, self.page.view.scene, "equip", self.skillData.fullname, utils.math.numberToString(self.skillData.cost, 2)) +end + +function SkillWidget:selectAction() + self.page:setMessage(self.skillData.description) +end + +return StatPage diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/statpage.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/statpage.lua new file mode 100644 index 0000000..4401ec3 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/character/statpage.lua @@ -0,0 +1,88 @@ +local PageParent = require "scenes.overworld.screens.mainmenu.character.pageparent" +local StatPage = PageParent:extend() + +local menu = require "game.modules.menus.list" +local gui = require "game.modules.gui" +local const = require "scenes.overworld.screens.mainmenu.const" + +local EquipMenu = menu.ListMenu:extend() +local EquipWidget = menu.DualTextWidget:extend() + +local STATS = require "datas.consts.stats" + +function StatPage:new(view, character) + self.statBox = gui.newTextBox("assets/gui/dialogbox.png", const.CHARPAGESIZE, 40 + 32) + + StatPage.super.new(self, view, character, {"Remove item"}) +end + +function StatPage:getCustomMenus() + return EquipMenu(self) +end + +function StatPage:menuResponses(i) + self.view.scene.menusystem:switchMenu("equip") +end + +function StatPage:draw() + self:drawStats(const.X, 100) +end + +function StatPage:drawStats(x, y) + love.graphics.draw(self.statBox, x, y) + + local char = self.character + for i, statName in ipairs(STATS.LIST) do + local xStat = x + (((i - 1) % 2) * (const.CHARPAGESIZE/2)) + 6 + local yStat = y + (math.floor((i-1)/2) * 16) + 4 + local middle = xStat + 10 + const.CHARPAGESIZE/4 + local stat = char.stats:get(statName) + self.view.scene.assets.fonts["small"]:draw(STATS.SIMPLENAME[statName], xStat, yStat, const.CHARPAGESIZE, "left") + self.view.scene.assets.fonts["small"]:setColor(1, 1, 1, 0.9) + self.view.scene.assets.fonts["small"]:draw(stat, middle, yStat, -1, "center") + self.view.scene.assets.fonts["small"]:setColor(1, 1, 1, 1) + utils.graphics.resetColor() + end +end + +function StatPage:removeEquip(type) + self.character:removeEquip(type) +end + +function EquipMenu:new(page) + self.page = page + EquipMenu.super.new(self, page.view.scene, "equip", const.X, const.Y + 4, const.CHARPAGESIZE, 3, true, true) + EquipWidget(page, "gloves") + EquipWidget(page, "shoes") + EquipWidget(page, "accessories") +end + +function EquipMenu:cancelAction() + self.scene.menusystem.menus["menu"]:getFocus() + self.scene.assets.sfx["mBack"]:play() +end + +function EquipWidget:new(page, type) + self.page = page + self.type = type + local label = self:getLabel() + EquipWidget.super.new(self, self.page.view.scene, "equip", label, "") +end + +function EquipWidget:getLabel() + local obj = self.page.character.equip[self.type] + if (utils.string.isEmpty(obj)) then + return "No " .. self.type + end + local data = core.datas:get("items", obj) + return data.fullname +end + +function EquipWidget:action() + self.page:removeEquip(self.type) + self.label = self:getLabel() + self:redrawCanvas() + self.scene.assets.sfx["mSelect"]:play() +end + +return StatPage diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/common/charmenu.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/common/charmenu.lua new file mode 100644 index 0000000..6ec5cbc --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/common/charmenu.lua @@ -0,0 +1,12 @@ +local baseMenu = require "game.modules.menus.parents.menu" +local CharacterMenu = baseMenu:extend() + +local const = require "scenes.overworld.screens.mainmenu.const" + +function CharacterMenu:new(scene, x) + local x = x or const.X + 136 + local w = const.WIDTH - x + 28 + CharacterMenu.super.new(self, scene, "character", x, const.Y, w, const.HEIGHT, 4) +end + +return CharacterMenu diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/common/charwidget.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/common/charwidget.lua new file mode 100644 index 0000000..c4fddf0 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/common/charwidget.lua @@ -0,0 +1,65 @@ +local baseWidget = require "game.modules.menus.parents.widget" +local CharacterWidget = baseWidget:extend() + +local ComplexHPBar = require "game.modules.gui.complexhpbar" +local Emblem = require "game.modules.gui.emblem" + +-- Hero custom widget +-- +function CharacterWidget:new(scene, name, showEquip) + self.charName = name + self.emblem = Emblem(game.characters.list[name], scene) + self.font2 = scene.assets.fonts["hudnbrs_small"] + self.showEquip = showEquip + CharacterWidget.super.new(self, scene, "character") + + self.hpbar = ComplexHPBar(88) + self.ppbar = ComplexHPBar(88) + self.hpbar:setColorForeground(248 / 255, 160 / 255, 0, 1) + self.hpbar:setColorBackground(112 / 255, 0, 0) + self.ppbar:setColorForeground(0, 248 / 255, 248 / 255, 1) + self.ppbar:setColorBackground(0, 54 / 255, 229 / 255) +end + +function CharacterWidget:drawCanvas() + local character = game.characters.list[self.charName] + self.font:setFilter("shadow") + local debut = 0 + local xDebut = 32 + self.font:draw(character.fullname, xDebut, debut, -1, "left") + if (self.showEquip == nil) then + local yLvl = debut + 16 + local xLvl = xDebut + self.scene.assets.images["lvl"]:draw(xLvl, yLvl) + self.scene.assets.images["exp"]:draw(xLvl, yLvl + 10) + self.font2:print(character.level, xLvl + 19, yLvl, "left") + local expString = character.exp .. "/" .. character.exp_next + self.font2:print(expString, xLvl + 19, yLvl + 10, "left") + else + local charEquip = character.equip[self.showEquip] + local equipString = "None" + if (not utils.string.isEmpty(charEquip)) then + local data = core.datas:get("items", charEquip) + equipString = data.fullname + end + self.font:draw(equipString, xDebut, debut + 16, -1, "left") + end +end + +function CharacterWidget:draw(x, y) + local character = game.characters.list[self.charName] + self.emblem:draw(x, y + 6) + if (self.showEquip == nil) then + local xDebut = x + 52 + local yDebut = y + 15 + self.scene.assets.fonts["hudnbrs_small"]:set() + local stats = character.stats + self.hpbar:drawWithLabels(xDebut + 53, yDebut, character.hp, stats:get(stats.HPMAX)) + self.ppbar:drawWithLabels(xDebut + 64, yDebut + 11, character.pp, stats:get(stats.PPMAX)) + end + if self.canvas.texture ~= nil then + love.graphics.draw(self.canvas.texture, x - self.ox, y - self.oy) + end +end + +return CharacterWidget diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/const.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/const.lua new file mode 100644 index 0000000..59dc89c --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/const.lua @@ -0,0 +1,11 @@ +local ConstMenu = {} + +ConstMenu.X = 28 +ConstMenu.Y = 40 +ConstMenu.WIDTH = 424 - 56 +ConstMenu.HEIGHT = 240 - 80 +ConstMenu.X2 = 424 - 28 +ConstMenu.Y2 = 240 - 40 +ConstMenu.CHARPAGESIZE = 176 + +return ConstMenu diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/equip.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/equip.lua new file mode 100644 index 0000000..51bd2cb --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/equip.lua @@ -0,0 +1,115 @@ +local ParentScreen = require "scenes.overworld.screens.parent" +local EquipScreen = ParentScreen:extend() + +local menu = require "game.modules.menus.list" +local const = require "scenes.overworld.screens.mainmenu.const" +local gui = require "game.modules.gui" + +local baseCharacterMenu = require "scenes.overworld.screens.mainmenu.common.charmenu" +local baseCharacterWidget = require "scenes.overworld.screens.mainmenu.common.charwidget" +local CharacterMenu = baseCharacterMenu:extend() +local CharacterWidget = baseCharacterWidget:extend() + +local STATS = require "datas.consts.stats" + +local DESC_SIZE = 32 * 6 + +function EquipScreen:new(scene, category, item, widgetId) + self.category = category + self.item = item + self.itemData = core.datas:get("items", self.item.name) + self.widgetId = widgetId + + self.choiceBack = gui.newChoiceBack(48 + 16) + self.descBox = gui.newTextBox("assets/gui/dialogbox.png", DESC_SIZE, 40 + 48+16) + + self.desc = self.itemData.description + self.charName = "" + EquipScreen.super.new(self, scene, "Equipement") +end + +function EquipScreen:setMenu() + CharacterMenu(self.scene, 224) + for i, name in ipairs(game.characters.team) do + CharacterWidget(self.scene, name, self.category) + end + self.scene.menusystem:switchMenu("character") +end + +function EquipScreen:draw() + self.scene.assets.fonts["small"]:setLineHeight(16 / 18) + self:drawPocket() + self:drawDescription(const.X, const.Y) +end + +function EquipScreen:drawDescription(x, y) + love.graphics.draw(self.descBox, x, y) + local xx, yy, ww = x + 6, y + 4, DESC_SIZE - 12 + self.scene.assets.fonts["small"]:draw(self.itemData.fullname, xx, yy, ww, "left") + if (self.charName ~= "") then + local char = game.characters.list[self.charName] + for i, statName in ipairs(STATS.LIST) do + local xStat = xx + (((i - 1) % 2) * (ww/2)) + local yStat = yy + (math.floor((i-1)/2) * 16) + 24 + local middle = xStat + 10 + ww/4 + local stat = char.stats:get(statName) + local newStat = char:predictStat(statName, self.category, self.item.name) + self.scene.assets.fonts["small"]:draw(STATS.SIMPLENAME[statName], xStat, yStat, ww, "left") + self.scene.assets.fonts["small"]:setColor(1, 1, 1, 0.9) + self.scene.assets.fonts["small"]:draw(stat .. " ", middle, yStat, -1, "right") + self.scene.assets.fonts["small"]:draw(">", middle, yStat, -1, "center") + if (newStat > stat) then + self.scene.assets.fonts["small"]:setColor(0.3, 1, 0.3, 0.9) + elseif (newStat < stat) then + self.scene.assets.fonts["small"]:setColor(1, 0.3, 0.3, 0.9) + end + + self.scene.assets.fonts["small"]:draw(" " .. newStat, middle, yStat, -1, "left") + self.scene.assets.fonts["small"]:setColor(1, 1, 1, 1) + utils.graphics.resetColor() + end + end +end + +function EquipScreen:drawPocket() + local x = const.X + DESC_SIZE - 48 + local y = const.Y2 - 24 + love.graphics.draw(self.choiceBack, x, y) + + self.scene.assets.fonts["small"]:draw("x" .. self.item.number, x + 16, y - 2, -1, "left") +end + +function EquipScreen:goBack() + self.scene.screens.mainmenu["items"](self.scene, game.loot:getPocketIdByName(self.category), self.widgetId) +end + +function EquipScreen:useItem(charName) + local character = game.characters.list[charName] + if (self.item.number <= 1) then + character:setEquip(self.category, self.item.name) + self:goBack() + else + character:setEquip(self.category, self.item.name) + end +end + +-- Character menu +function CharacterMenu:cancelAction() + -- Switch à l'écran précédant + self.scene.assets:playSFX("mBack") + self.scene.currentScreen:goBack() +end + +-- Hero custom widget +-- +function CharacterWidget:selectAction() + self.scene.currentScreen.charName = self.charName +end + +function CharacterWidget:action() + self.scene.assets:playSFX("mSelect") + self.scene.currentScreen:useItem(self.charName) + self:redrawCanvas() +end + +return EquipScreen diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/init.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/init.lua new file mode 100644 index 0000000..423dc7d --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/init.lua @@ -0,0 +1,7 @@ +return { + pause = require "scenes.overworld.screens.mainmenu.pause", + character = require "scenes.overworld.screens.mainmenu.character", + items = require "scenes.overworld.screens.mainmenu.items", + useItems = require "scenes.overworld.screens.mainmenu.useitems", + equip = require "scenes.overworld.screens.mainmenu.equip" +} diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/items.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/items.lua new file mode 100644 index 0000000..65e1308 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/items.lua @@ -0,0 +1,258 @@ +local ParentScreen = require "scenes.overworld.screens.parent" +local ItemsScreen = ParentScreen:extend() + +local menu = require "game.modules.menus.list" +local const = require "scenes.overworld.screens.mainmenu.const" +local gui = require "game.modules.gui" + +local ItemWidget = menu.DualTextWidget:extend() +local BackWidget = menu.DualTextWidget:extend() +local ResumeWidget = menu.DualTextWidget:extend() +local DropWidget = menu.DualTextWidget:extend() +local UseWidget = menu.DualTextWidget:extend() + +local DESC_SIZE = 48*4 + +local ConfirmDialog = require "game.modules.confirmdialog" + +function ItemsScreen:new(scene, menuIndex, widgetIndex) + self.menuIndex = menuIndex or 1 + self.widgetIndex = widgetIndex or 1 + self.choiceBack = gui.newChoiceBack(DESC_SIZE) + self.descBox = gui.newTextBox("assets/gui/dialogbox.png", DESC_SIZE, 40+16) + self.effectBox = gui.newTextBox("assets/gui/dialogbox.png", DESC_SIZE, 40) + self.desc = "" + self.effects = "" + ItemsScreen.super.new(self, scene, "Items") +end + +function ItemsScreen:update(dt) + if (self.scene.menusystem.menus["useMenu"] == nil) then + local keys = self.scene:getKeys(1) + if (keys["left"].isPressed) then + self.widgetIndex = 1 + self:getMenu(self.menuIndex - 1) + self.scene.assets.sfx["mBeep"]:play() + end + if (keys["right"].isPressed) then + self.widgetIndex = 1 + self:getMenu(self.menuIndex + 1) + self.scene.assets.sfx["mBeep"]:play() + end + end +end + +function ItemsScreen:getMenu(newMenuIndex) + local newMenuIndex = newMenuIndex or 1 + if (newMenuIndex > #game.loot.inventory) then + newMenuIndex = 1 + end + if (newMenuIndex < 1) then + newMenuIndex = #game.loot.inventory + end + + self.menuIndex = newMenuIndex + self.scene.menusystem:reset() + self:setMenu() +end + +function ItemsScreen:setMenu(widgetId) + self.pocket = game.loot:getPocketById(self.menuIndex) + local w = 128+32 + menu.ListMenu(self.scene, "menu", const.X2 - w, const.Y + 8, w, 9, true) + for i,item in ipairs(self.pocket.list) do + --menu.DualTextWidget(self.scene, "menu", item.name, "x" .. item.number) + ItemWidget(self.scene, self.pocket.name, item, i) + end + BackWidget(self.scene) + self.scene.menusystem.menus["menu"]:setCancelWidget() + self.scene.menusystem:switchMenu("menu") + self.scene.menusystem.menus["menu"].isLocked = true + self.scene.menusystem.menus["menu"].widget.selected = math.max(1, self.widgetIndex) + self.scene.menusystem.menus["menu"].cursorTransition = math.max(0, self.widgetIndex - 1) + self.scene.menusystem:setSoundFromSceneAssets("mBeep") +end + +function ItemsScreen:setUseMenu(item, widgetId) + local w = 96 + menu.ListMenu(self.scene, "useMenu", const.X2 + 16 - w, const.Y2 - 48, w, 3, true) + UseWidget(self.scene, self.pocket.name, item, widgetId) + DropWidget(self.scene, self.pocket.name, item, widgetId) + ResumeWidget(self.scene) + self.scene.menusystem.menus["useMenu"]:setCancelWidget() + self.scene.menusystem:switchMenu("useMenu") + self.scene.menusystem.menus["useMenu"]:setDepth(-1) +end + +function ItemsScreen:removeUseMenu() + self.scene.menusystem.menus["useMenu"]:destroy() + self.scene.menusystem:switchMenu("menu") +end + +function ItemsScreen:draw() + self:drawPocket() + self:drawDescription(const.X, const.Y2 - (88+16)) + self:drawEffects(const.X, const.Y2 - 40) +end + +function ItemsScreen:drawDescription(x, y) + love.graphics.draw(self.descBox, x, y) + local xx, yy, ww = x + 6, y + 4, DESC_SIZE - 12 + self.scene.assets.fonts["small"]:draw(self.desc, xx, yy, ww, "left") +end + +function ItemsScreen:drawEffects(x, y) + love.graphics.draw(self.effectBox, x, y) + local xx, yy, ww = x + 6, y + 4, DESC_SIZE - 12 + self.scene.assets.fonts["small"]:draw(self.effects, xx, yy, ww, "left") +end + +function ItemsScreen:drawPocket() + local middleX = ((16) + (DESC_SIZE - 24)) / 2 + love.graphics.draw(self.choiceBack, const.X, const.Y) + + self.scene.assets.fonts["small"]:draw("<", const.X + 16, const.Y - 2, -1, "left") + self.scene.assets.fonts["small"]:draw(">", const.X + DESC_SIZE - 24, const.Y - 2, -1, "right") + self.scene.assets.fonts["small"]:draw(self.pocket.fullname, const.X + middleX, const.Y - 2, -1, "center") + + self:drawPocketRoll(const.X + 48*2, const.Y + 20) +end + +function ItemsScreen:drawPocketRoll(x, y) + core.screen:setScissor(const.X, const.Y+ 16, 48*4, 48) + + local trueX = x - ((self.menuIndex - 1) * 32) + for i, pocket in ipairs(game.loot.inventory) do + local trueIndex = i - self.menuIndex + if (trueIndex > 4) then + trueIndex = trueIndex - 8 + end + if (trueIndex < -4) then + trueIndex = trueIndex + 8 + end + if (trueIndex ~= 0) then + love.graphics.setColor(.3, .3, .3, .6) + end + self.scene.assets.tileset["itembox"]:drawTile(i, x + ((trueIndex)*32), y, 0, 1, 1, 14, 0) + utils.graphics.resetColor() + end + + core.screen:resetScissor() +end + +-- Items Widgets +function ItemWidget:new(scene, pocket, item, widgetId) + self.item = item + self.itemData = core.datas:get("items", self.item.name) + self.pocket = pocket + self.widgetId = widgetId + ItemWidget.super.new(self, scene, "menu", self.itemData.fullname, "x" .. utils.math.numberToString(self.item.number, 2)) +end + +function ItemWidget:selectAction() + self.scene.currentScreen.desc = self.itemData.description + self.scene.currentScreen.effects = game.loot:getEffectStrings(self.pocket, self.item.name) +end + +function ItemWidget:action() + self.scene.assets:playSFX("mSelect") + self.scene.currentScreen:setUseMenu(self.item, self.widgetId) +end + +function BackWidget:new(scene) + ItemWidget.super.new(self, scene, "menu", "Back", "") +end + +function BackWidget:selectAction() + self.scene.currentScreen.desc = "" + self.scene.currentScreen.effects = "" +end + +function BackWidget:action() + self.scene.assets:playSFX("mBack") + self.scene.screens.mainmenu["pause"](self.scene, "main", 3) +end + +-- Use Menu Widget + +function UseWidget:new(scene, pocket, item, widgetId) + self.item = item + self.itemData = core.datas:get("items", self.item.name) + self.pocket = pocket + self.pocketData = game.loot:getPocketByName(self.pocket) + self.widgetId = widgetId + UseWidget.super.new(self, scene, "useMenu", "Use", "") + if (not (self.itemData.usableOnMap or self.pocketData.isEquipement)) then + self.color = {0.6, 0.6, 0.6} + end +end + +function UseWidget:action() + if (self.pocketData.isEquipement) then + self.scene.screens.mainmenu["equip"](self.scene, self.pocket, self.item, self.widgetId) + self.scene.assets:playSFX("mSelect") + elseif (self.itemData.usableOnMap) then + self.scene.screens.mainmenu["useItems"](self.scene, self.pocket, self.item, self.widgetId) + self.scene.assets:playSFX("mSelect") + else + self.scene.assets:playSFX("mError") + end +end + +function DropWidget:new(scene, pocket, item, widgetId) + self.item = item + self.itemData = core.datas:get("items", self.item.name) + self.pocket = pocket + self.max = self.item.number + self.widgetId = widgetId + self.number = 1 + DropWidget.super.new(self, scene, "useMenu", "Drop", "<" .. utils.math.numberToString(self.number, 2) .. ">") +end + +function DropWidget:updateSelected() + local keys = self.scene:getKeys(1) + if (keys["left"].isPressed) then + if (self.number > 1) then + self.number = self.number - 1 + else + self.number = self.max + end + self.label2 = "<" .. utils.math.numberToString(self.number, 2) .. ">" + self:invalidateCanvas() + end + if (keys["right"].isPressed) then + if (self.number < self.max) then + self.number = self.number + 1 + else + self.number = 1 + end + self.label2 = "<" .. utils.math.numberToString(self.number, 2) .. ">" + self:invalidateCanvas() + end +end + +function DropWidget:action() + self.scene.assets:playSFX("mSelect") + local confirm = ConfirmDialog(self.scene, "Do you want to drop these items ? \nYou won't be able to recover them.", + function() self:drop() end) + confirm:setCancelChoice(2) + confirm.autoDismiss = true +end + +function DropWidget:drop() + game.loot:removeItem(self.pocket, self.item.name, self.number) + self.scene.currentScreen.widgetIndex = self.widgetId + self.scene.currentScreen:removeUseMenu() + self.scene.currentScreen:setMenu() +end + +function ResumeWidget:new(scene) + ResumeWidget.super.new(self, scene, "useMenu", "Back", "") +end + +function ResumeWidget:action() + self.scene.assets:playSFX("mBack") + self.scene.currentScreen:removeUseMenu() +end + +return ItemsScreen diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/pause.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/pause.lua new file mode 100644 index 0000000..c73f79c --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/pause.lua @@ -0,0 +1,137 @@ +local ParentScreen = require "scenes.overworld.screens.parent" +local PauseScreen = ParentScreen:extend() + +local menu = require "game.modules.menus.fancy" + +local baseCharacterMenu = require "scenes.overworld.screens.mainmenu.common.charmenu" +local baseCharacterWidget = require "scenes.overworld.screens.mainmenu.common.charwidget" +local CharacterMenu = baseCharacterMenu:extend() +local CharacterWidget = baseCharacterWidget:extend() + +local TeamWidget = menu.BaseWidget:extend() +local ViewWidget = menu.BaseWidget:extend() +local SaveExitWidget = menu.BaseWidget:extend() + +local defTransitions = require "birb.modules.transitions" +local radTransitions = require "game.modules.transitions" +local ConfirmDialog = require "game.modules.confirmdialog" + +local const = require "scenes.overworld.screens.mainmenu.const" + +function PauseScreen:new(scene, menu, widget) + self.menuSelected = menu or "main" + self.widgetSelected = widget + self.widget = widget + PauseScreen.super.new(self, scene, "Menu") +end + +function PauseScreen:setMenu() + menu.FancyMenu(self.scene, "main", const.X, const.Y, 108, 10, false) + TeamWidget(self.scene) + menu.BaseWidget(self.scene, "main", "Quest", ">") + ViewWidget(self.scene, "Items", "items") + menu.BaseWidget(self.scene, "main", "Chao", ">") + menu.BaseWidget(self.scene, "main", "Encylopedia", ">") + --menu.BaseWidget(self.scene, "main", "Options", ">") + self.scene.menusystem.menus["main"]:addSubMenu("save", "Save / Exit") + SaveExitWidget(self.scene, "main", "Resume", false, false) + + SaveExitWidget(self.scene, "save", "Save game", true, false) + SaveExitWidget(self.scene, "save", "Save and exit", true, true) + SaveExitWidget(self.scene, "save", "Exit game", false, true) + + self.scene.menusystem.menus["main"]:finalize() + self.scene.menusystem.menus["main"]:setCancelWidget() + + CharacterMenu(self.scene) + for i, name in ipairs(game.characters.team) do + CharacterWidget(self.scene, name) + end + self.scene.menusystem.menus["character"].isLocked = true + + self.scene.menusystem:switchMenu(self.menuSelected) + self.scene.menusystem.menus["main"].isVisible = true + if (self.widgetSelected ~= nil) then + self.scene.menusystem.menus[self.menuSelected].widget.selected = self.widgetSelected + self.scene.menusystem.menus[self.menuSelected].cursorTransition = self.widgetSelected - 1 + end + self.scene.menusystem:setSoundFromSceneAssets("mBeep") +end + +function PauseScreen:draw() + +end + +-- Character menu +function CharacterMenu:cancelAction() + self.scene.assets:playSFX("mBeep") + self.scene.menusystem:switchMenu("main") +end + +-- Hero custom widget +-- +function CharacterWidget:action() + self.scene.assets:playSFX("mSelect") + self.scene.screens.mainmenu.character(self.scene, self.charName) +end + +-- Team Widget +-- + +function TeamWidget:new(scene) + TeamWidget.super.new(self, scene, "main", "Team", ">") +end + +function TeamWidget:action() + self.scene.assets:playSFX("mBeep") + self.scene.menusystem.menus["character"]:getFocus() +end + +-- View Widget +function ViewWidget:new(scene, name, view) + TeamWidget.super.new(self, scene, "main", name, ">") + self.nextView = view +end + +function ViewWidget:action() + self.scene.assets:playSFX("mSelect") + self.scene.screens.mainmenu[self.nextView](self.scene) +end + +-- Save & Exit Widget +function SaveExitWidget:new(scene, menu, name, save, exit) + SaveExitWidget.super.new(self, scene, menu, name, "") + self.exit = exit + self.save = save +end + +function SaveExitWidget:action() + if (self.save or self.exit) then + self.scene.assets:playSFX("mSelect") + else + self.scene.assets:playSFX("mBack") + end + if (self.save) then + self.scene.world:savePosition() + game:write() + end + if (self.exit) then + if (self.save) then + self:exitToMenu() + else + local confirm = ConfirmDialog(self.scene, "Do you to exit the game ? \nAll unsaved data will be lost.", + function() self:exitToMenu() end) + confirm:setCancelChoice(2) + end + else + self.scene:unpause() + end +end + +function SaveExitWidget:exitToMenu() + core.screen:startTransition(defTransitions.default, defTransitions.circle, function() game:reload() scenes.menus.main() end, 424/2, 240/2) + self.scene.tweens:newTween(0, 0.3, {ringBorder=-16}, "inOutQuad") + self.scene.tweens:newTween(0, 0.3, {timeBorder=-20}, "inOutQuad") +end + +return PauseScreen diff --git a/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/useitems.lua b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/useitems.lua new file mode 100644 index 0000000..795dad2 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/mainmenu/useitems.lua @@ -0,0 +1,91 @@ +local ParentScreen = require "scenes.overworld.screens.parent" +local UseItemsScreen = ParentScreen:extend() + +local menu = require "game.modules.menus.list" +local const = require "scenes.overworld.screens.mainmenu.const" +local gui = require "game.modules.gui" + +local baseCharacterMenu = require "scenes.overworld.screens.mainmenu.common.charmenu" +local baseCharacterWidget = require "scenes.overworld.screens.mainmenu.common.charwidget" +local CharacterMenu = baseCharacterMenu:extend() +local CharacterWidget = baseCharacterWidget:extend() + +local EffectManager = require "game.loot.effectManager" + +local DESC_SIZE = 32 * 4 + +function UseItemsScreen:new(scene, category, item, widgetId) + UseItemsScreen.super.new(self, scene, "Use item") + self.category = category + self.item = item + self.itemData = core.datas:get("items", self.item.name) + self.widgetId = widgetId + + self.choiceBack = gui.newChoiceBack(48 + 16) + self.descBox = gui.newTextBox("assets/gui/dialogbox.png", DESC_SIZE, 40 + 48) + + self.desc = self.itemData.description + self.effects = game.loot:getEffectStrings(self.category, self.item.name) + + self.effectManager = EffectManager() + self.effectManager:getItemData(category, self.item.name) +end + +function UseItemsScreen:setMenu() + CharacterMenu(self.scene) + for i, name in ipairs(game.characters.team) do + CharacterWidget(self.scene, name) + end + self.scene.menusystem:switchMenu("character") +end + +function UseItemsScreen:draw() + self.scene.assets.fonts["small"]:setLineHeight(16 / 18) + self:drawPocket() + self:drawDescription(const.X, const.Y) +end + +function UseItemsScreen:drawDescription(x, y) + love.graphics.draw(self.descBox, x, y) + local xx, yy, ww = x + 6, y + 4, DESC_SIZE - 12 + self.scene.assets.fonts["small"]:draw(self.itemData.fullname .. ":\n" .. self.effects, xx, yy, ww, "left") +end + +function UseItemsScreen:drawPocket() + local x = const.X + DESC_SIZE - 48 + local y = const.Y2 - 24 + love.graphics.draw(self.choiceBack, x, y) + + self.scene.assets.fonts["small"]:draw("x" .. self.item.number, x + 16, y - 2, -1, "left") +end + +function UseItemsScreen:goBack() + self.scene.screens.mainmenu["items"](self.scene, game.loot:getPocketIdByName(self.category), self.widgetId) +end + +function UseItemsScreen:useItem(charName) + local character = game.characters.list[charName] + self.effectManager:applyEffects(character) + if (self.item.number <= 1) then + game.loot:removeItem(self.category, self.item.name, 1) + self:goBack() + else + game.loot:removeItem(self.category, self.item.name, 1) + end +end + +-- Character menu +function CharacterMenu:cancelAction() + -- Switch à l'écran précédant + self.scene.assets:playSFX("mBack") + self.scene.currentScreen:goBack() +end + +-- Hero custom widget +-- +function CharacterWidget:action() + self.scene.assets:playSFX("mSelect") + self.scene.currentScreen:useItem(self.charName) +end + +return UseItemsScreen diff --git a/sonic-bluestreak.love/scenes/overworld/screens/menu.lua b/sonic-bluestreak.love/scenes/overworld/screens/menu.lua new file mode 100644 index 0000000..9a46d31 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/menu.lua @@ -0,0 +1,103 @@ +local ListBox = require "birb.modules.menusystem.listbox" +local Widget = require "birb.modules.menusystem.widgets" + +local menu = {} +menu.CustomMenu = ListBox:extend() +menu.BasicMenu = ListBox:extend() +menu.BoxedMenu = menu.BasicMenu:extend() +menu.BasicWidget = Widget.Text:extend() +menu.BoxedWidget = menu.BasicWidget:extend() + +local CONST = {} +CONST.MENU = {} +CONST.MENU.ITEM_HEIGHT = 16 + +local gui = require "game.modules.gui" + +-- Custom Menu +function menu.CustomMenu:new(scene, name, x, y, w, h, itemNumber) + self.scene = scene + menu.CustomMenu.super.new(self, scene.menusystem, name, x, y, w, h, itemNumber) +end + +-- Basic menu +function menu.BasicMenu:new(scene, name, itemNumber, x, y, w) + self.scene = scene + local h = itemNumber * CONST.MENU.ITEM_HEIGHT + menu.BasicMenu.super.new(self, scene.menusystem, name, x, y, w, h, itemNumber) + self.cursorTexture = love.graphics.newImage("assets/gui/cursor-menulist.png") + self.cursorTransition = 0 +end + +function menu.BasicMenu:update(dt) + menu.BasicMenu.super.update(self, dt) + + local relativecursor = self.widget.selected - self.view.firstSlot + + local transition = self.cursorTransition - relativecursor + + if math.abs(transition) < 0.1 then + self.cursorTransition = relativecursor + else + self.cursorTransition = (self.cursorTransition) + ((relativecursor) - (self.cursorTransition)) * dt*45 + end + +end + +function menu.BasicMenu:drawCursor() + local addition = 17 + local x = self.x - 1 + local y = self.y + ((self.cursorTransition) * addition) + 1 + love.graphics.draw(self.cursorTexture, x, y) +end + +-- Boxed menu +function menu.BoxedMenu:new(scene, name, itemNumber, x, y, w) + menu.BoxedMenu.super.new(self, scene, name, itemNumber, x, y, w) + self.box = gui.newTextBox("assets/gui/dialogbox.png", self.w+16, self.h+16) +end + +function menu.BoxedMenu:draw() + love.graphics.draw(self.box, self.x-8, self.y-8) + menu.BoxedMenu.super.draw(self) +end + +-- Basic Widget +function menu.BasicWidget:new(scene, menu_name, label, label2) + local font = scene.assets.fonts["small"] + self.scene = scene + local widgetMenu = scene.menusystem.menus[menu_name] + self.label2 = label2 or "" + menu.BasicWidget.super.new(self, widgetMenu, font, label) +end + +function menu.BasicWidget:drawCanvas() + local h = math.floor(self.height / 2) - (self.font:getHeight() / 2) + love.graphics.setColor(0, 0, 0, 1) + self.font:print(self.label, 9, h, "left") + self.font:print(self.label2, self.width - 7, h, "right") + utils.graphics.resetColor() + self.font:print(self.label, 8, h, "left") + self.font:print(self.label2, self.width - 8, h, "right") +end + +-- Basic Widget +function menu.BoxedWidget:new(scene, menu_name, label, label2) + menu.BoxedWidget.super.new(self, scene, menu_name, label, label2) + self.box = gui.newChoiceBack(self.menu.w + 24) +end + +function menu.BoxedWidget:drawCanvas() + love.graphics.draw(self.box, 0, 0) + + local h = math.floor(self.height / 2) - (self.font:getHeight() / 2) - 1 + love.graphics.setColor(0, 0, 0, .8) + self.font:print(self.label, 17, h, "left") + self.font:print(self.label2, self.width - 8, h, "right") + utils.graphics.resetColor() + self.font:print(self.label, 16, h, "left") + self.font:print(self.label2, self.width - 9, h, "right") +end + + +return menu diff --git a/sonic-bluestreak.love/scenes/overworld/screens/parent.lua b/sonic-bluestreak.love/scenes/overworld/screens/parent.lua new file mode 100644 index 0000000..061077b --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/screens/parent.lua @@ -0,0 +1,49 @@ +local MenuScreenParent = Object:extend() + +local menu = require "scenes.overworld.screens.menu" +local const = require "scenes.overworld.screens.mainmenu.const" + +function MenuScreenParent:new(scene, title) + self.scene = scene + self.menusystem = scene.menusystem + + self.menuObj = menu + + self.title = title or "" + + self.scene:registerScreen(self) + self:setMenu() +end + +function MenuScreenParent:update(dt) + +end + +function MenuScreenParent:setMenu() + +end + +function MenuScreenParent:quit() + self.scene.menusystem:reset() + self.scene:quitScreen() +end + +function MenuScreenParent:drawForeground() + self.scene.assets.fonts["SA2font"]:print(self.title, 160, 12) + --love.graphics.rectangle("line", const.X, const.Y, const.WIDTH, const.HEIGHT) + self:draw() +end + + +function MenuScreenParent:draw() + +end + +function MenuScreenParent:drawBackground() + +end + +function MenuScreenParent:drawOverEverything() +end + +return MenuScreenParent diff --git a/sonic-bluestreak.love/scenes/overworld/world.lua b/sonic-bluestreak.love/scenes/overworld/world.lua new file mode 100644 index 0000000..619ec08 --- /dev/null +++ b/sonic-bluestreak.love/scenes/overworld/world.lua @@ -0,0 +1,46 @@ +local World = require "birb.modules.world.world2D" +local RPGWorld = World:extend() +local objFile = "scenes.overworld.actors" +local RPGMap = require "scenes.overworld.map" + +function RPGWorld:new(scene, area, playerx, playery) + self.area = area or game.position.area + self.playerx = playerx or game.position.x + self.playery = playery or game.position.y + RPGWorld.super.new(self, scene, objFile, nil, nil) +end + +function RPGWorld:createMapController() + RPGMap(self, self.area, self.playerx, self.playery) +end + +function RPGWorld:savePosition() + local x, y = self.players[1].actor.x, self.players[1].actor.y + game.position.x = math.floor(x / 16) + game.position.y = math.floor(y / 16) + game.position.area = self.area +end + +function RPGWorld:teleport(area, x, y, charDir) + if (area == self.area) then + self.players[1].actor.x = x * 16 + self.players[1].actor.y = y * 16 + else + self.area = area + self.playerx = x + self.playery = y + self:reset() + collectgarbage() + self.players[1].actor.charDir = charDir + end +end + +function RPGWorld:restoreActions() + self.encounter:destroy() + local currentMap = self.map:getMapAtPoint(self.players[1].actor.x, self.players[1].actor.y) + self.players[1].actor.xsp = 0 + self.players[1].actor.ysp = 0 + self.scene:playMapMusic(currentMap) +end + +return RPGWorld diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/actor-index.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/actor-index.lua deleted file mode 100644 index 96ad0b5..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/actor-index.lua +++ /dev/null @@ -1,9 +0,0 @@ -local ActorIndex = {} -local folder = "scenes.subgame.sonic-boost.actors." - -local Actor = folder .. "actors" - -ActorIndex[1] = Actor.Ring -ActorIndex[2] = Actor.Crystal - -return ActorIndex diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/block.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/block.lua deleted file mode 100644 index 293ec1a..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/block.lua +++ /dev/null @@ -1,12 +0,0 @@ -local folder = "scenes.subgame.sonic-boost.actors." - -local Entity = require(folder .. "parent") - -function Block:new(level, x, y, z, w, h, d) -- On enregistre une nouvelle entité, avec par défaut sa hitbox. - Block.super.new(self, level, "block", x-16, y-10, 0, 31, 20, d) - self.name = "block" - - self:setDebugColor(255, 0, 0) -end - -return Block diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/character.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/character.lua deleted file mode 100644 index 7fe4771..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/character.lua +++ /dev/null @@ -1,540 +0,0 @@ -local folder = "scenes.subgame.sonic-boost.actors." - -local Entity = require(folder .. "parent") -local phys = require "datas.gamedata.physics" -local playerHeight = 32 -local grindheight = 32 - -local Character = Entity:extend() - --- Un "personnage" est une entité unique, dans le sens où elle possède un controller --- special, qui fait le lien entre elle et les différents éléments du niveau - --- Le code des personnages normaux et rivaux est exactement le même, les différence --- sont géré par les controlleurs, qui s'occupent de leur envoyer les données --- de touche, et d'effecter les réactions logique en cas de disparition de l'entité --- (terminer le niveau pour un joueur, juste le détruire pour un rival) - --- Le personnage ne sait pas à l'intérieur de lui même s'il est contrôler par une --- IA ou par un vrai joueur. - --- Il n'a pas non plus accès aux détails de la mission, qui sont aussi géré par --- son controller special (vu par "self.charcontroller") - -function Character:new(charcontroller, rail, character, id) - self.charcontroller = charcontroller - local world = self.charcontroller.controller.world - - - local rail = rail or 2 - local y = 10 + (rail*20) - Character.super.new(self, world, "character", 16-8, y-8, 0, 16, 16, playerHeight) - self.name = "player" - self.charid = id or 1 - - self.yspeed = 0 - self.xspeed = 0 - self.zspeed = 0 - - self.ymove = false - self.onGround = true - self.groundBellow = true - self.groundTerrain = 0 - self.isJumping = false - self.isInAerialAction = false - self.canAerialAction = true - self.isInAction = false - self.canAction = true - - self.dash = false - self.dashCam = false - - self:setDebugColor(0, 255, 0) - - self:characterInit(character) - - self:setSprite("character" .. self.charid, 32, 48, true) - - self.depth = -1 - - self.rings = 0 - self.score = 0 - self.combo = 0 - self.bonus = 0 - self.turn = 1 - - self.life = 3 - - self.startx = self.x - self.starty = self.y - - self.view = {} - self.view.x = self.x - self.view.y = self.y - self.view.dx = 0 - - self.relx = 0 - self.relxspeed = 0 - - self.grind = false - - self.ai = isAIControlled or false -end - -function Character:characterInit(char) - self.data = game.characters:getCharacterData(char) - - self.lifeicon = self.data.assets.lifeicon -end - -function Character:update(dt) - self:updateTimers(dt) - - -- On initialise les variables de directions - local dx, dy, dz = 0, 0, 0 - - -- On commence par récupérer les inputs fait sur le pad virtuel, qui est géré - -- dans core.input.keys. On le garde dans une variable qui sera utilisée dans - -- tout l'objet joueur - - self.groundTerrain, self.groundBellow = self:getTerrain() - - self.keys = self.charcontroller:getKeys() - - self:sideSteps() - self:jumpAction() - self:jump() - self:normalAction() - - self:applyVerticalVelocity(dt) - - self:autoMove(dt) - self:snaptoRails(dt) - - self:move() -end - --- ACTIONS FUNCTIONS -- - -function Character:sideSteps() - if self.grind == true then - if (self.keys["up"].isPressed) then - self.yspeed = - 1 * 60 * phys.side - self.ymove = true - elseif (self.keys["down"].isPressed) then - self.yspeed = 60 * phys.side - self.ymove = true - else - self.ymove = false - end - else - if (self.keys["up"].isDown) then - self.yspeed = - 1 * 60 * phys.side - self.ymove = true - elseif (self.keys["down"].isDown) then - self.yspeed = 60 * phys.side - self.ymove = true - else - self.ymove = false - end - end -end - -function Character:jump() - if (self.keys["A"].isPressed) and (self.onGround) then - self.zspeed = 60 * self.data.stats.jmp - self.onGround = false - self.isJumping = true - self.isInAction = false - end -end - -function Character:jumpAction() - if self.data.stats.jumpaction == "doublejump" then - if (self.keys["A"].isPressed) and (self.isJumping) and (self.canAerialAction) then - self.zspeed = 60 * self.data.stats.jumpaction_power - self.isInAerialAction = true - self.canAerialAction = false - end - elseif self.data.stats.jumpaction == "jumpdash" then - if (self.keys["A"].isPressed) and (self.isJumping) and (self.canAerialAction) then - self.zspeed = 60 * 1 - self.xspeed = math.max(self.xspeed, self.data.stats.spd * 60 * 1.2) - self.isInAerialAction = true - self.canAerialAction = false - self.dashCam = true - self:addTimer("dashCam", .5) - end - end -end - -function Character:normalAction() - if self.data.stats.action == "spinattack" then - if (self.keys["B"].isPressed) and (self.onGround) and (self.canAction) and (self.grind == false) then - self.xspeed = math.max(self.xspeed, self.data.stats.spd * 60 * 1.5) - self.isInAction = true - self.canAction = false - self.dashCam = true - self:addTimer("action", .5) - self:addTimer("action_cooldown", 1) - self:addTimer("dashCam", .5) - end - end -end - --- Moving functions -- - -function Character:move() - local cols, coll_number - - self:setFilter() - - self:updateRelativePosition() - - self.x, self.y, self.z, cols, coll_number = Character.super.move(self) - - for i=1, coll_number do - local col = cols[i] - if col.other.type == "collectible" then - col.other:pickedUp(self) - end - self.collisionResponse(cols[i]) - end - -end - -function Character:updateRelativePosition() - local MAXVIEW = 80 - local MINVIEW = -20 - if not ((self.onGround == false) and (self.z < 0)) then - if (self.dashCam) or (self.dash) then - self.relx = math.min(self.relx + 0.4, MAXVIEW) - else - if self.keys["left"].isDown then - if self.relx > 0 then - self.relx = math.max(self.relx - 0.3, 0) - elseif self.relx <= 0 then - self.relx = math.max(self.relx - 0.1, MINVIEW) - end - elseif self.keys["right"].isDown then - if self.relx >= 0 then - if self.relx <= MAXVIEW*3/4 then - self.relx = math.min(self.relx + 0.2, MAXVIEW*3/4) - else - self.relx = math.max(self.relx - 0.1, MAXVIEW*3/4) - end - elseif self.relx < 0 then - self.relx = math.min(self.relx + 0.3, 0) - end - else - if self.relx > 0 then - self.relx = math.max(self.relx - 0.3, 0) - elseif self.relx < 0 then - self.relx = math.min(self.relx + 0.3, 0) - end - end - end - end - - self.x = self.view.x + self.relx -end - -function Character:getViewCenter() - local x, y, z - x = math.floor(self.view.x + self.w / 2) - y = math.floor(self.y + self.h / 2) - z = math.floor(self.z + self.d / 2) - - return x, y, z -end - -function Character:collisionResponse(other) - if other == nil then return 0 end - if other.type == "collectible" then - other:pickedUp() - end -end - -function Character:setFilter() - self.filter = function(item, other) - if other.type == "collectible" then return "cross" - else return "cross" end - end -end - -function Character:autoMove(dt) - local max = self.data.stats.spd - self.lockspeed = false - - - - - acc = phys.acc - - if (self.groundTerrain == 1) and (self.z <= 0) then - self.dash = true - self:addTimer("dash", 2) - acc = phys.acc - end - - if (self.groundTerrain == 2) and (self.z <= 0) then - max = phys.max * 1/3 - self.dash = false - self.acc = acc*2 - end - - if (self.groundTerrain == 4) and (self.z <= 0) then - self.dash = true - self:addTimer("dash", 2) - self.zspeed = 60 * (phys.spring * 4/5) - self.onGround = false - self.isJumping = true - self.assets.sfx["jumpboard"]:play() - end - - if (self.groundTerrain == 3) and (self.z <= 0) then - max = 0 - self.dash = false - self.acc = acc*3 - self.xspeed = self.xspeed * 3/4 - --self.lockspeed = true - end - - if (self.lockspeed == false) then - if self.dash == true then - self.xspeed = max * 60 * phys.boost - elseif self.grind == true then - self.xspeed = max * 60 - else - if self.xspeed < (max*60) then - self.xspeed = self.xspeed + acc - elseif (self.xspeed - acc*2) > (phys.max*60) then - self.xspeed = self.xspeed - acc*2 - else - self.xspeed = (max*60) - end - end - - self.view.x = self.view.x + self.xspeed * dt - end - - if self.x >= self.controller.world.width then - self:overflowLevel() - end -end - - -function Character:applyVerticalVelocity(dt) - if (self.groundBellow == false) and (self.onGround == true) then - self.onGround = false - end - - local grindBellow = self.world:getGrindAtPoint(self.x, self.y, self.turn) - - if (grindBellow == false) and (self.onGround == true) and self.z > 0 then - self.onGround = false - self.grind = false - end - - if (self.onGround == false) then - self.zspeed = self.zspeed - phys.grv - - if self.zspeed < 0 then - if (self.z + self.zspeed*dt <= 0) and (self.groundBellow == true) then - self.z = 0 - self.onGround = true - self.isJumping = false - self.grind = false -- pas vraiment nécessaire de retirer le grind ici - self.isInAerialAction = false - self.canAerialAction = true - end - - if (self.z + self.zspeed*dt <= grindheight) and (self.z + self.zspeed*dt > grindheight - 8) and (grindBellow == true) then - self.z = grindheight - self.onGround = true - self.isJumping = false - self.grind = true - self.isInAerialAction = false - self.canAerialAction = true - end - - - if (self.groundBellow == false) and (self.z < -64) then - self:die() - end - end - self.z = self.z + self.zspeed*dt - end - - if self.ground == true then - self.zspeed = 0 - end -end - -function Character:snaptoRails(dt) - local centery = self.y + 8 - local yrail = math.floor((centery - 10) / 20) - local newyrail = math.floor((centery + self.yspeed*dt - 10) / 20) - - if (newyrail < 0) and (self.yspeed < 0) then - centery = 10 - self.yspeed = 0 - elseif (newyrail >= 4) and (self.yspeed > 0) then - centery = 90 - self.yspeed = 0 - else - if (self.ymove == false) and (yrail ~= newyrail) then - if self.yspeed > 0 then - centery = newyrail * 20 + 10 - end - if self.yspeed < 0 then - centery = yrail * 20 + 10 - end - self.yspeed = 0 - else - centery = centery + self.yspeed*dt - end - end - - self.y = centery - 8 -end - ----------- INTERACTION FUNCTIONS --------- - -function Character:getTerrain() - local terrain, groundbellow - terrain = self.world:getTerrainAtPoint(self.x, self.y, self.turn) - - if (terrain == 3) then - groundbellow = false - else - groundbellow = true - end - - return terrain, groundbellow -end - -function Character:addScore(score) - self.combo = self.combo + 1 - - self.bonus = math.floor(self.combo / 5) * 2 - - self.score = self.score + score + math.floor(1/10 * score * self.bonus) - - self:addTimer("combo", 3) -end - ----------- DRAWING FUNCTIONS --------- - -function Character:animations() - self.assets.sprites["character" .. self.charid]:setCustomSpeed(math.abs(self.xspeed / 16)) - - if self.onGround then - if self.grind == true then - self:setAnimation("grind") - elseif self.isInAction == true then - self:setAnimation("action") - else - if self.xspeed == 0 then - self:setAnimation("idle") - elseif self.xspeed < phys.max*60 then - self:setAnimation("run2") - elseif self.xspeed >= phys.max*60 then - self:setAnimation("dash") - end - end - else - if self.isJumping then - self:setAnimation("jump") - else - self:setAnimation("fall") - end - end -end - -function Character:setAnimation(animation) - if (self.animation ~= animation) then - self.animation = animation - self.assets.sprites["character" .. self.charid]:changeAnimation(animation, true) - end -end - -function Character:draw() - self:animations() - if (self.z < 0) and (self.onGround == false) then - z = self.z - if self.z < -48 then z = -48 end - love.graphics.setScissor(0, 0, 424, self.y + 100) - end - self:drawSprite() - love.graphics.setScissor() -end - -function Character:drawEcho() - self:animations() - if (self.z < 0) and (self.onGround == false) then - z = self.z - if self.z < -48 then z = -48 end - love.graphics.setScissor(0, 0, 424, self.y + 100) - end - self:drawSprite(self.world.width, 0) - love.graphics.setScissor() -end - -function Character:drawShadow(tx, ty) - if (self.z < 0) and (self.onGround == false) then - return 0 - end - Character.super.drawShadow(self, tx, ty) -end - -function Character:drawShadowEcho() - if (self.z < 0) and (self.onGround == false) then - return 0 - end - Character.super.drawShadow(self, self.world.width, 0) -end - ----------- LEVEL FINISH FUNCTIONS ---------- - -function Character:overflowLevel() - self.charcontroller:newLap() -end - -function Character:finishLevel() - --love.event.quit() -end - -function Character:die() - if self.life == 0 then - self.charcontroller:die() - else - self.life = self.life - 1 - self.view.x = self.startx - self.relx = 0 - self.dash = false - self.dashCam = false - self.y = self.starty - self.z = 0 - self.rings = 0 - end -end - ------ TIMERS ----- - -function Character:endedTimer(name) - if name == "dash" then - self.dash = false - elseif name == "combo" then - self.combo = 0 - self.bonus = 0 - elseif name == "action" then - self.isInAction = false - elseif name == "dashCam" then - self.dashCam = false - elseif name == "action_cooldown" then - self.canAction = true - end -end - -return Character diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/crystal.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/crystal.lua deleted file mode 100644 index 3eb5b0f..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/crystal.lua +++ /dev/null @@ -1,23 +0,0 @@ -local folder = "scenes.subgame.sonic-boost.actors." - -local Entity = require(folder .. "parent") -local Crystal = Entity:extend() - -function Crystal:new(world, x, y, z) - local z = z or 8 - Crystal.super.new(self, world, "collectible", x-8, y-8, z, 16, 16, 16) - - self:setSprite("crystal", 8, 16, true) - - self:setDebugColor(255, 255, 0) - - self.depth = 1 -end - -function Crystal:pickedUp(player) - player:addScore(10) - - self:destroy() -end - -return Crystal diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/init.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/init.lua deleted file mode 100644 index 55bec06..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/init.lua +++ /dev/null @@ -1,14 +0,0 @@ -local Actor = {} - -local folder = "scenes.subgame.sonic-boost.actors." - -Actor.Character = require(folder .. "character") -Actor.Ring = require(folder .. "ring") -Actor.Crystal = require(folder .. "crystal") -Actor.Rail = require(folder .. "rail") - -Actor.Index = {} -Actor.Index[01] = Actor.Ring -Actor.Index[02] = Actor.Crystal - -return Actor diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/parent.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/parent.lua deleted file mode 100644 index 1d0d92f..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/parent.lua +++ /dev/null @@ -1,228 +0,0 @@ -local folder = "scenes.subgame.sonic-boost.actors." -local ParentEntity = Object:extend() -- On créer la classe des entitées, c'est la classe de base - -local Timer = require(folder .. "utils.timers") - -function ParentEntity:new(world, type, x, y, z, w, h, d) -- On enregistre une nouvelle entité, avec par défaut sa hitbox. - self:setHitbox(x, y, z, w, h, d) - self:register(world) - --self:initPhysics() - --self:resetTimers() - self:setDebugColor(0,0,0) - self.destroyed = false - self.invisible = false - self.appearence = "none" - - self.type = type - - self:setSprite("", 0, 0, false) - - self:setFilter() - - self.depth = 0 - self.id = self.world.creationID - self.world.creationID = self.world.creationID + 1 - - self:resetTimers() -end - -function ParentEntity:setHitbox(x, y, z, w, h, d) - self.x = x - self.y = y - self.z = z - self.w = w - self.h = h - self.d = d -end - -function ParentEntity:setSprite(name, ox, oy, active) - self.sprite = {} - - self.sprite.name = name - self.sprite.ox = ox - self.sprite.oy = oy - self.sprite.active = active or false -end - -function ParentEntity:update(dt) - self:updateTimers(dt) -end - -function ParentEntity:register(world) - -- On enregistre la hitbox dans le monde, pour l'instant les deux parties du programmes - -- sont séparé (génération et enregistrement, peut-être qu'elles seront fusionnées) - self.world = world - self.controller = world.controller - self.assets = self.controller.assets - - self.world:register(self) -end - -function ParentEntity:destroy() - if self.destroyed == false then - self.world:remove(self) - self.destroyed = true - end -end - -function ParentEntity:move() - local x, y, z, cols, coll_number = self.x, self.y, self.z, {}, 0 - if self.destroyed == false then - x, y, z, cols, coll_number = self.world:move( - self, - self.x, - self.y, - self.z, - self.filter - ) - end - - return x, y, z, cols, coll_number -end - -function ParentEntity:drawDebug() - if self.invisible == true then - return 0 - end - - self:draw() -end - ---------------------------- DEBUG FUNCTIONS ------------------------------------ - -function ParentEntity:setDebugColor(r,g,b) - self.debugColor = {} - - self.debugColor.r = r - self.debugColor.g = g - self.debugColor.b = b -end - ----------- COLLISION ---------- - -function ParentEntity:setFilter() - self.filter = function(item, other) - return nil - end -end - -function ParentEntity:set2DFilter() - self.filter2D = function(item, other) - return "cross" - end -end - -function ParentEntity:pickedUp() - self:destroy() -end - ---------------------------- COORDINATE FUNCTIONS ------------------------------------ - -function ParentEntity:getCenter() - local x, y, z - x = math.floor(self.x + self.w / 2) - y = math.floor(self.y + self.h / 2) - z = math.floor(self.z + self.d / 2) - - return x, y, z -end - -function ParentEntity:getViewCenter() - return self:getCenter() -end - -function ParentEntity:getOrigin() - local x, y, z - y = math.floor(self.y + self.h / 2) - x = math.floor(self.x + self.w / 2) + math.floor(y / 2) - z = math.floor(self.z) - - return x, y, z -end - -function ParentEntity:getSpritePosition() - local x, y, z = self:getOrigin() - y = y - z - - return x, y, z -end - ---------------------------- DRAW FUNCTIONS ------------------------------------ - -function ParentEntity:draw() - self:drawSprite() -end - -function ParentEntity:drawEcho() - self:drawSprite(self.world.width, 0) -end - -function ParentEntity:drawSprite(tx, ty) - utils.graphics.resetColor() - - local x, y, z = self:getSpritePosition() - - local tx = tx or 0 - local ty = ty or 0 - - if (self.sprite.active) then - self.assets.sprites[self.sprite.name]:drawAnimation(x + tx, y + ty, 0, 1, 1, self.sprite.ox, self.sprite.oy) - end -end - -function ParentEntity:drawShadow(tx, ty) - local x, y, z = self:getOrigin() - utils.graphics.resetColor() - local tx = tx or 0 - local ty = ty or 0 - x = math.floor(x + tx) - y = math.floor(y + ty) - self.assets:drawImage("shadow", x, y, 0, 1, 1, 12, 3) -end - -function ParentEntity:drawShadowEcho() - self:drawShadow(self.world.width, 0) -end - -function ParentEntity:drawHitBox() - x, y, z = self:getOrigin() - - local r, g, b, a = self.debugColor.r, self.debugColor.g, self.debugColor.b, self.debugColor.a - - --utils.graphics.box(self.x, self.y + self.z + self.h, self.w, self.d, self.h, r, g, b, a) - --utils.graphics.box(x - (self.w/2), y - (self.w/2) - self.z, self.w, self.h, r, g, b, a) - --utils.graphics.box(x - (self.w/2), y - (self.w/2) - self.z, self.w, self.d, r, g, b, a) - --utils.graphics.box(x - (self.w/2), y + (self.w/2) - self.z - self.d, self.w, self.d, r, g, b, a) - --utils.graphics.box(x - (self.w/2), y - (self.w/2) - self.z - self.d, self.w, self.h, r, g, b, a) - --utils.graphics.box(x - (self.w/2), y + (self.w/2) - self.z - self.d, self.w, self.d, r, g, b, a) - - utils.graphics.box(x - (self.w/2), y - (self.h/2), self.w, self.h, r/5, g/5, b/5, 1) - - utils.graphics.box(x - (self.w/2), y - z - self.d, self.w, self.d, r, g, b, 1) - -end - ------------ TIMER RELATED FUNCTIONS ---------- - -function ParentEntity:resetTimers() - self.timers = {} -end - -function ParentEntity:addTimer(name, t) - self.timers[name] = Timer(self, name, t) - return name -end - -function ParentEntity:updateTimers(dt) - for i, v in pairs(self.timers) do - v:update(dt) - end -end - -function ParentEntity:endedTimer(name) - if name == "destroy" then - self:destroy() - end -end - -return ParentEntity diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/rail.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/rail.lua deleted file mode 100644 index c7634eb..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/rail.lua +++ /dev/null @@ -1,27 +0,0 @@ -local folder = "scenes.subgame.sonic-boost.actors." - -local Entity = require(folder .. "parent") -local Rail = Entity:extend() - -function Rail:new(world, x, y, z, id) - local z = z or 32 - self.railid = id or 2 - - Rail.super.new(self, world, "grind", x, y-4, 24, 31, 8, 8) - - self:setDebugColor(.2, .2, .2) - - self.depth = 1 -end - -function Rail:draw() - utils.graphics.resetColor( ) - love.graphics.draw(self.world.textures.rail, self.world.quads.rails[self.railid], self.x + math.floor(self.y / 2), self.y - self.z -(self.d / 2)) -end - -function Rail:drawEcho() - utils.graphics.resetColor( ) - love.graphics.draw(self.world.textures.rail, self.world.quads.rails[self.railid], self.x + math.floor(self.y / 2) + self.world.width, self.y - self.z -(self.d / 2)) -end - -return Rail diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/ring.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/ring.lua deleted file mode 100644 index 52c1000..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/ring.lua +++ /dev/null @@ -1,24 +0,0 @@ -local folder = "scenes.subgame.sonic-boost.actors." - -local Entity = require(folder .. "parent") -local Ring = Entity:extend() - -function Ring:new(world, x, y, z) - local z = z or 8 - Ring.super.new(self, world, "collectible", x-8, y-8, z, 16, 16, 16) - - self:setSprite("ring", 8, 16, true) - - self:setDebugColor(255, 255, 0) - - self.depth = 1 -end - -function Ring:pickedUp(player) - player.rings = player.rings + 1 - player:addScore(10) - - self:destroy() -end - -return Ring diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/utils/timers.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/utils/timers.lua deleted file mode 100644 index 05fabdd..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/actors/utils/timers.lua +++ /dev/null @@ -1,21 +0,0 @@ -local Timer = Object:extend() - -function Timer:new(entity, name, t) - self.time = t - self.entity = entity - self.name = name -end - -function Timer:update(dt) - self.time = self.time - dt - if (self.time <= 0) then - self:finish() - end -end - -function Timer:finish() - self.entity:endedTimer(self.name) - self.entity.timers[self.name] = nil -end - -return Timer diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/background.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/background.lua deleted file mode 100644 index 60705c8..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/background.lua +++ /dev/null @@ -1,53 +0,0 @@ -local Background = Object:extend() - -function Background:new(controller, levelname) - self.controller = controller - local filename = self.controller.datas.background or "forest" - local backfolder = "assets/backgrounds/sideview/parallax/" - filename = backfolder .. filename - self.back1 = love.graphics.newImage(filename .. "-back.png") - self.back2 = love.graphics.newImage(filename .. "-fore.png") -end - -function Background:destroy() - self.back1:release( ) - self.back2:release( ) -end - -function Background:draw() - local x0, x1, x2 - - local turn = self.controller.camera.turn - - x0 = self.controller.camera.view.x + (turn * self.controller.world.width) - x1 = x0 / 3 % 240 - x2 = x0 / 9 % 480 - - local sx = 1 - for i=1, 4 do - if (i == 2) or (i == 4) then - love.graphics.draw(self.back1, (i)*240 - x2, 20, 0, -1, 1) - else - love.graphics.draw(self.back1, (i-1)*240 - x2, 20, 0, 1, 1) - end - end - - for i=1, 3 do - love.graphics.draw(self.back2, (i-1)*240 - x1, 20, 0, 1, 1) - end - - --self:drawBorders() - --self:drawGround(0, 90) -end - -function Background:drawGround(x, y) - for i=1, 5 do - for j=1, 16 do - local k = 1 + ((i + j) % 2) - print(k) - love.graphics.draw(self.normalTileImage, self.normalTile[k], x + (j-3)*31 + (i-1)*10 , y + (i-1)*20) - end - end -end - -return Background diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/camera.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/camera.lua deleted file mode 100644 index 97fd9f4..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/camera.lua +++ /dev/null @@ -1,122 +0,0 @@ -local Camera = require "libs.hump.camera" -local CameraSystem = Object:extend() - -function CameraSystem:new(controller, x, y, target) - self.controller = controller - self.target = target - self.view = Camera(212, 30, 1, 0, true) - local width, height, flags = love.window.getMode( ) - self.screen = {} - self.screen.width = width - self.screen.height = height - self.width = 424 - self.height = 240 - self.resolution = self.screen.width / self.width - --self:limit() - - self.turn = 1 -end - -function CameraSystem:setTarget(target) - self.target = target -end - -function CameraSystem:floorCoord() - self.view.x, self.view.y = utils.math.floorCoord(self.view.x, self.view.y) -end - -function CameraSystem:update() - if (self.target ~= nil) then - self:followEntity(self.target) - end - self:limit() - self:floorCoord() -end - -function CameraSystem:move(x, y) - self.view.x = x - self.view.y = y - - self:limit() -end - -function CameraSystem:getCoord() - local camx, camy, camh, camw - camx = self.view.x - (self.width/2) - camy = self.view.y - (self.height/2) - - camw = self.width - camh = self.height - return camx, camy, camw, camh -end - -function CameraSystem:worldCoord(x, y, ox, oy, w, h) - ox, oy = ox or 0, oy or 0 - w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() - return self.view:worldCoords(x, y, ox, oy, w, h) -end - -function CameraSystem:viewCoord(x, y) - return self.view:cameraCoords(x, y, ox, oy, w, h) -end - -function CameraSystem:getScreenCoord() - local camx, camy, camh, camw - camx = self.view.x - (self.screen.width/2) - camy = self.view.y - (self.screen.height/2) - - camw = self.screen.width - camh = self.screen.height - return camx, camy, camw, camh -end - -function CameraSystem:limit() - local camx, camy = self.view.x, self.view.y - - local currentTurn, maxTurn = self.turn, self.controller.missiondata.turns - - if currentTurn == 1 then - camx = math.max(212, camx) - end - - if currentTurn == maxTurn then - camx = math.min(camx, self.controller.world.width - 212 + 31) - end - - self.view.x, self.view.y = camx, 30 -end - -function CameraSystem:followEntity(entity) - local entity = entity - - if (entity ~= nil) then - self.turn = entity.turn or 1 - - local playx, playy = entity:getViewCenter() - - local camx, camy = self.view.x + (self.width/2), - self.view.y + (self.height/2) - - - playx, playy = self:viewCoord(playx-16+212, 30) - playx = playx - (self.width/2) - playy = playy - (self.height/2) - - if (math.abs(playx) > 8) then - camx = camx + (playx - (8*utils.math.sign(playx))) - end - - if (playy > 16) then - camy = camy + (playy - 16) - elseif (playy < -64) then - camy = camy + (playy + 64) - end - - self.view.x, self.view.y = camx - (self.width/2), - camy - (self.height/2) - end -end - --- Anciennes Fonctions - -return CameraSystem diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/characters.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/characters.lua deleted file mode 100644 index 98ea74d..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/characters.lua +++ /dev/null @@ -1,125 +0,0 @@ -local CharManager = Object:extend() -local Dummy = Object:extend() -local Player = Dummy:extend() -local Rival = Dummy:extend() -local actor = require "scenes.subgame.sonic-boost.actors" - - -function CharManager:new(controller) - self.controller = controller - self.list = {} -end - -function CharManager:newPlayer(character, rail) - local id = #self.list + 1 - table.insert(self.list, Player(self, id, character, rail)) -end - -function CharManager:newDummy(character, rail) - local id = #self.list + 1 - table.insert(self.list, Dummy(self, id, character, rail)) -end - -function CharManager:update(dt) - for i,v in ipairs(self.list) do - v:update(dt) - end -end - -function CharManager:getType(id) - self.list[id]:getType() -end - --- DUMMY CHARACTER FUNCTION -- - -function Dummy:new(manager, playerid, character, rail) - self.manager = manager - self.controller = manager.controller - self.type = "dummy" - - local character = character or "sonic" - - local rail = rail - - local spritepath = "assets/sprites/characters/subgame/sonic-boost/" .. character - self.controller.assets:addSprite("character" .. playerid, spritepath) - - self.actor = actor.Character(self, rail, character, playerid) -end - - -function Dummy:getKeys() - return core.input.fakekeys -end - -function Dummy:update(dt) - -- le Dummy ne fait rien, donc inutile -end - -function Dummy:newLap() - local currentTurn, maxTurn = self.actor.turn, self.controller.missiondata.turns - - if (currentTurn < maxTurn) then - self:wrapActor() - else - self:finishLevel() - end -end - -function Dummy:wrapActor() - self.actor.x = math.floor(self.actor.x - self.controller.world.width) - self.actor.turn = self.actor.turn + 1 -end - -function Dummy:getRealPosition() - local turn = self.actor.turn - 1 -- on calcule le tour à partir de 0 pour - -- obtenir le vrai x. Techniquement, ça ne change rien pour le joueur, - -- mais c'est plus correct comme ça - - local turnStart = (turn * self.controller.world.width) - - return turnStart + self.actor.x -end - -function Dummy:finishLevel() - -- Pour le Dummy ça n'a aucun effet -end - -function Dummy:die() - self.actor:destroy() -end - --- PLAYER CONTROL FUNCTION -- - -function Player:new(manager, playerid, character, rail) - Player.super.new(self, manager, playerid, character, rail) - - self.type = "player" - self.controller.camera:setTarget(self.actor) - self.controller.hud:setTarget(self.actor) -end - -function Player:getKeys() - if self.controller.areInputsLocked then - self.controller.areInputsLocked = false - return core.input.fakekeys - else - return self.controller:getKeys(1); - end -end - -function Player:wrapActor() - self.actor.view.x = math.floor(self.actor.view.x - self.controller.world.width) - self.actor.turn = self.actor.turn + 1 - self.controller.camera.view.x = self.controller.camera.view.x - self.controller.world.width -end - -function Player:finishLevel() - --love.event.quit() -end - -function Player:die() - love.event.quit() -end - -return CharManager diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/hud.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/hud.lua deleted file mode 100644 index ea19903..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/hud.lua +++ /dev/null @@ -1,133 +0,0 @@ -local BattleHUD = Object:extend() - -local gui = require "game.modules.gui" - -function BattleHUD:new(controller) - self.controller = controller - self.target = nil - - self:loadAssets() -end - -function BattleHUD:setTarget(target) - self.target = target -end - -function BattleHUD:loadAssets() - self.progressbarImage = love.graphics.newImage("assets/gui/hud/progressbar.png") - self.barBack = love.graphics.newQuad(0, 0, 211, 12, 211, 24) - self.barFore = love.graphics.newQuad(0, 12, 211, 12, 211, 24) - self.hud1 = gui.newBorder(424, 20, 14) - self.hud2 = gui.newBorder(424, 40, 12) - - self.ring = love.graphics.newImage("assets/gui/hud/ring.png") - - - - self.font = love.graphics.newImageFont("assets/gui/hud/numbers.png", " 0123456789:/", 1) - self.font2 = love.graphics.newImageFont("assets/gui/hud/smallnumbers.png", " 0123456789", 0) - - self.time = love.graphics.newImage("assets/gui/hud/time.png") - self.score = love.graphics.newImage("assets/gui/hud/score.png") - self.bonus = love.graphics.newImage("assets/gui/hud/bonus.png") - - self.controller.assets:addTileset("lifeicon", "assets/sprites/characters/charicons") -end - -function BattleHUD:destroy( ) - self.progressbarImage:release( ) - self.barBack:release( ) - self.barFore:release( ) - self.hud1:release( ) - self.hud2:release( ) -end - -function BattleHUD:update(dt) - -- -end - -function BattleHUD:draw() - love.graphics.setFont( self.font ) - self:drawFrame() - - if self.target ~= nil then - self:drawTop(0, 0) - self:drawBottom(0, 200) - end - - self.controller:resetFont( ) -end - -function BattleHUD:drawFrame() - love.graphics.setColor(0.256, 0.632, 0.852, 1) - love.graphics.rectangle("fill", 0, 0, 424, 20) - love.graphics.rectangle("fill", 0, 200, 424, 20) - utils.graphics.resetColor() - love.graphics.draw(self.hud1, 0, 0, 0, 1, -1, 0, 20) - love.graphics.draw(self.hud2, 0, 200, 0, -1, 1, 424, 0) -end - -function BattleHUD:drawTop(x, y) - - local ringx, ringy = x + 289, y + 6 - love.graphics.draw(self.ring, ringx, ringy) - local rings = utils.math.numberToString(self.target.rings, 3) - - love.graphics.print(rings, ringx + 14, ringy + 1) - - - love.graphics.draw(self.score, x+8, y+3) - local score = utils.math.numberToString(self.target.score, 9) - local bonus = utils.math.numberToString(self.target.bonus, 3) - local combo = utils.math.numberToString(self.target.combo, 3) - - love.graphics.print(score, x + 8 + 42, y + 4) - - local bonusx, bonusy = x + 165, y + 1 - love.graphics.draw(self.bonus, bonusx, bonusy) - love.graphics.setFont( self.font2 ) - love.graphics.print(combo, bonusx + 28, bonusy) - love.graphics.print(bonus, bonusx + 28, bonusy + 8) - love.graphics.setFont( self.font ) - - self.controller.assets.tileset["lifeicon"]:drawTile(self.target.lifeicon, x + 360, y + 4) - local lives = utils.math.numberToString(self.target.life, 2) - love.graphics.print(lives, x + 360 + 18, y + 7 ) -end - -function BattleHUD:drawBottom(x, y) - local progressx, progressy = x + 204, y + 4 - love.graphics.draw(self.progressbarImage, self.barBack, progressx, progressy) - local width = math.floor((self.target.x / self.controller.world.width) * (211 - 16)) - width = math.max(0, width) - width = math.min(width, (211 - 16)) - love.graphics.setScissor(progressx + 8, progressy, width, 12) - love.graphics.draw(self.progressbarImage, self.barFore, progressx, progressy) - love.graphics.setScissor( ) - self.controller.assets.tileset["lifeicon"]:drawTile(self.target.lifeicon, progressx + width, progressy - 2) - if (self.controller.missiondata.turns > 1) then - local turn1 = utils.math.numberToString(self.target.turn, 2) - local turn2 = utils.math.numberToString(self.controller.missiondata.turns, 2) - love.graphics.printf(turn1 .. "/" .. turn2, progressx, progressy + 12 + 2, 210, "right") - end - - local timex, timey = x + 5, y + 2 - love.graphics.draw(self.time, timex, timey) - local timestring = self:getTimeString(self.controller.mission.timer) - - love.graphics.print(timestring, timex + 32, timey + 1) - - -end - -function BattleHUD:getTimeString(numberOfSeconds) - local numberOfSeconds = numberOfSeconds or 0 - local microseconds = math.floor((numberOfSeconds % 1) * 100) - local seconds = math.floor(numberOfSeconds % 60) - local minutes = math.floor(numberOfSeconds / 60) - return utils.math.numberToString(minutes, 2) .. ":" - .. utils.math.numberToString(seconds, 2) .. ":" - .. utils.math.numberToString(microseconds, 2) -end - -return BattleHUD diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/loader.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/loader.lua deleted file mode 100644 index 79a3a32..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/loader.lua +++ /dev/null @@ -1,82 +0,0 @@ -local Loader = Object:extend() - -function Loader:new(controller) - self.controller = controller - self.assetQueue = {} - self.pointer = 1 - self.finished = false -end - -function Loader:addElement(type, name, filepath, arg1, arg2, arg3, arg4) - local queueElement = {} - - queueElement.type = type - queueElement.name = name - queueElement.file = filepath - table.insert(self.assetQueue, queueElement) - - self.finished = false -end - -function Loader:update(dt) - -end - -function Loader:treatAssetQueueElement(id) - if self.assetQueue[id] ~= nil then - local asset = self.assetQueue[id] - if asset.type == "image" then - self.controller.assets:addImage(asset.name, asset.file) - elseif asset.type == "sprite" then - self.controller.assets:addSprite(asset.name, asset.file) - elseif asset.type == "sfx" then - self.controller.assets:addSFX(asset.name, asset.file) - end - end -end - -function Loader:treatAssetQueue() - for i = self.pointer, 10 do - if i <= #self.assetQueue then - self.finished = true - end - end - self.pointer = i -end - -local function LoadAssets(controller) - controller.assets:addImage("shadow", "assets/sprites/shadow.png") - controller.assets:addSprite("ring", "assets/sprites/items/ring") - controller.assets:addSprite("crystal", "assets/sprites/items/crystal") - - controller.assets:addFont("text", "assets/fonts/PixelOperator.ttf", 16.5) - --controller.gui:addTextBox("solid", "assets/gui/dialogbox.png") - - controller.assets:addSFX("ring", "assets/sfx/gameplay/objects/ring.wav") - controller.assets:addSFX("booster", "assets/sfx/gameplay/objects/booster.wav") - controller.assets:addSFX("jumpboard", "assets/sfx/gameplay/objects/jumpboard.wav") - - controller.assets:addSFX("jump", "assets/sfx/gameplay/actions/jump-modern.wav") - controller.assets:addSFX("doublejump", "assets/sfx/gameplay/actions/doublejump.wav") - controller.assets:addSFX("spin", "assets/sfx/gameplay/actions/spin.wav") - - controller.assets:addSFX("grind", "assets/sfx/gameplay/grind/grind.wav") - controller.assets:addSFX("grindland", "assets/sfx/gameplay/grind/land.wav") - - controller.assets:addFont("menu", "assets/fonts/RussoOne-Regular.ttf", 15) - controller.assets.fonts["menu"]:setAlign("center") - controller.assets.fonts["menu"]:setFilter("border") - controller.assets.fonts["menu"]:setSpacing(true, 1) - - controller.assets:addFont("title", "assets/fonts/Teko-Bold.ttf", 22) - controller.assets.fonts["title"]:setAlign("center") - controller.assets.fonts["title"]:setFilter("doubleborder") - controller.assets.fonts["title"]:setSpacing(true, 2) - - controller.assets:addSFX("select", "assets/sfx/menu/select.wav") - controller.assets:addSFX("validate", "assets/sfx/menu/validate.wav") - controller.assets:addSFX("cancel", "assets/sfx/menu/cancel.wav") - -end - -return LoadAssets diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/pause.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/pause.lua deleted file mode 100644 index bd1a296..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/pause.lua +++ /dev/null @@ -1,66 +0,0 @@ -local ListBox = require "core.modules.menusystem.listbox" -local PauseMenu = ListBox:extend() - -local Widget = require "core.modules.menusystem.widgets" - -local ResumeWidget = Widget.Text:extend() -local RestartWidget = Widget.Text:extend() -local ExitWidget = Widget.Text:extend() - -function PauseMenu:new(controller) - local height, width, x, y - height = 72 - width = 72 - x = 424/2 - width/2 - y = 240/2 - height/2 - - PauseMenu.super.new(self, controller.menusystem, "pauseMenu", x, y, width, height, 3) - self.controller = controller - - self:setSound(self.controller.assets.sfx["select"]) - self.isActive = false - self.isVisible = false - - local font = self.controller.assets.fonts["menu"] - - ResumeWidget(self, font) - RestartWidget(self, font) - ExitWidget(self, font) -end - -function PauseMenu:draw() - PauseMenu.super.draw(self) -end - ---- MENU WIDGETS - -function ResumeWidget:new(menu, font) - ResumeWidget.super.new(self, menu, font, "resume") -end - -function ResumeWidget:action() - self.menu.isActive = false - self.menu.isVisible = false - self.menu.controller.assets.isActive = true - self.menu.controller:lockInputs() -end - -function RestartWidget:new(menu, font) - ResumeWidget.super.new(self, menu, font, "restart") -end - -function RestartWidget:action() - self.menu.controller:lockInputs() - self.menu.controller:restartLevel() -end - -function ExitWidget:new(menu, font) - ExitWidget.super.new(self, menu, font, "exit") -end - -function ExitWidget:action() - self.menu.controller:exitLevel() -end - - -return PauseMenu diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/world.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/world.lua deleted file mode 100644 index 110c20f..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/controller/world.lua +++ /dev/null @@ -1,511 +0,0 @@ -local World = Object:extend() - -local bump3dpd = require 'libs.level-libs.bump-3dpd' -local bump2d = require 'libs.level-libs.bump' -local tsort = require 'libs.level-libs.tsort' - -local actor = require "scenes.subgame.sonic-boost.actors" - -local tilesize = 31 - ----------- WORLD FUNCTIONS ---------- - -function World:new(controller) - self.controller = controller - self.creationID = 1 - - self.entities = bump3dpd.newWorld() - self.chunks = {} - - self:loadAssets() - - self.worldloaded = false -end - -function World:destroy() - self.chunks = {} - for i,v in ipairs(self.entities:getItems()) do - v:destroy( ) - end -end - ----------- ENTITIES MANAGEMENT FUNCTIONS ---------- - -function World:addEntitiesFromChunk(chunkpos) - local chunkdata, isTrue = self:getChunkData(chunkpos, 1) - local objectdata = chunkdata.objects - - local chunkx = (chunkpos - 1) * (8*31) - print("trying to get objects from chunk at pos " .. chunkpos) - - for i=1, 5 do - for j=1, 8 do - local y = (i-1)*20 + 10 - local x = chunkx + (j-1)*31 + 16 - - local id = objectdata[i][j] - --print(chunkpos) - self:addEntityFromID(id, x, y) - end - end -end - -function World:addRailsFromChunk(chunkpos) - local chunkdata, isTrue = self:getChunkData(chunkpos, 1) - local objectdata = chunkdata.grind - - local chunkx = (chunkpos - 1) * (8*31) - print("trying to get rails from chunk at pos " .. chunkpos) - - for i=1, 5 do - for j=1, 8 do - local y = (i-1)*20 + 10 - local x = chunkx + (j-1)*31 - - local id = objectdata[i][j] - --print(chunkpos) - if id ~= 0 then - actor.Rail(self, x, y, 10, id) - end - end - end -end - -function World:addEntityFromID(id, x, y) - if actor.Index[id] == nil then - if (id ~= 0) then - print("WARNING: Object " .. id .. " doesn't exist") - end - return false - end - - actor.Index[id](self, x, y) -end - -function World:register(entity) - self.entities:add(entity, entity.x, entity.y, entity.z, entity.w, entity.h, entity.d) -end - -function World:remove(entity) - if entity.destroyed == false then - self.entities:remove(entity) - print("entity " .. entity.id .. " removed") - end -end - -function World:move(entity, dx, dy, dz, filter) - local dx, dy, dz = dx, dy, dz - local newx, newy, newz - newx, newy, newz, cols, coll_number = self.entities:move(entity, dx, dy, dz, filter) - return newx, newy, newz, cols, coll_number -end - -function World:updateEntity(entity, dx, dy, dz) - newx, newy, newz, cols, coll_number = self.entities:update(entity, dx, dy, dz) -end - ----------- UPDATE FUNCTIONS ---------- - -function World:update(dt) - for _, item in ipairs(self.entities:getItems()) do - item:update(dt) - --self.world2D:update(item, item.x, item.y) - end -end - ----------- DRAW FUNCTIONS ---------- - - -function World:draw() - local chunksize = 8 * tilesize - local camstart = math.floor(math.max(0, (self.controller.camera.view.x - 212) / chunksize)) -- - - self:drawBorder(-10) - - for i=0, 3 do - -- on fait commencer la boucle à 0 pour regarder celui *avant* la caméra, - -- pour éviter des soucis d'affichage. - local chunkid = camstart + i - self:drawChunk((chunkid - 1) * chunksize, 0, chunkid) - end - - local itemsToDraw = self.entities:getItems() - - for _, item in ipairs(itemsToDraw) do - item:drawShadow() - if self.controller.camera.turn < self.controller.missiondata.turns then - item:drawShadowEcho() - end - end - - table.sort(itemsToDraw, sortItemsToDraw) - - for _, item in ipairs(itemsToDraw) do - item:draw() - if self.controller.camera.turn < self.controller.missiondata.turns then - item:drawEcho() - end - --item:drawHitBox() - end - - self:drawBorder(100) -end - -function World:drawChunk(x, y, chunkid, turn) - local chunkdata, isTrue = self:getChunkData(chunkid, self.controller.camera.turn) - local terraindata = chunkdata.terrain - - for i=1, 5 do - for j=1, 8 do - local tiley = (i-1)*20 - 4 - local tilex = x + (j-1)*31 + (i-1)*10 - local tileid = terraindata[i][j] - - local variant = 1 + ((i + j) % 2) - if (isTrue == false) then - love.graphics.setColor(.75, .75, .75, 1) - end - self:drawTile(tilex, tiley, tileid, variant) - utils.graphics.resetColor() - end - end -end - - -function World:drawTile(x, y, type, variant) - if type == 0 then - love.graphics.draw(self.textures.tiles, self.quads.tiles[variant], x, y) - else - love.graphics.draw(self.textures.sptiles, self.quads.sptiles[type], x, y-2) - end -end - -function World:drawBorder(y) - local x = math.floor((self.controller.camera.view.x - 212) / 80) * 80 - - for i=1, 7 do - love.graphics.draw(self.textures.borders, self.quads.borders, x + (i-1)*80, y, 0, 1, 1) - end -end - - - ----------- LOADING FUNCTIONS ---------- - -function World:loadWorld() - self.chunks = {} - - self:addChunk("basics", 00) - - local layout = self.controller.layout - for i,v in ipairs(layout) do - --print("Decompressing group of parts " .. i .. " located in " .. v[1] .. " (containing " .. #v[2] .. " parts)") - - -- self.controller.layout est un tableau composée d'une série de tableau, - -- chacuns en deux partie : le premier (v[1]) contient le nom du fichier - -- où se trouve des partie de niveau, et la seconde partie (v[2]) une liste - -- d'identifiant de partie de niveau à rajouter. - - -- Ce format permet de simplifier l'écriture de layout, si on a besoin de - -- plusieur partie de niveau se trouvant dans le même fichier. - - for j,w in ipairs(v[2]) do - -- On dit au gestionnaire de terrain d'ajouter la partie numéro j se trouvant - -- dans v[2]. Le nom du fichier contenant les parties sera toujours v[1] - self:addPart(v[1], w) - end - end -end - -function World:addPart(filename, part) - local filename = filename or "self" - local partdata = {} - - -- On recupère les données de chunks - - if (filename == "self") or (filename == "") then - - -- Si le nom est "self", cela veut dire que fichier est le même que celui ou - -- se trouve le layout, qui est forcément le fichier du niveau. Cela veut dire - -- qu'il faut utiliser les parties de niveau du niveau actuel, localisée dans - -- self.controller.parts - - partdata = self.controller.parts - else - - -- Si c'est un autre nom, on charge dans "partdata" la liste des partie de niveau - -- du fichier qu'on réfère. - - local chunkfile = require("datas.subgame.sonic-boost.chunks." .. filename) - partdata = chunkfile.parts - end - - -- On charge ensuite la partie de niveau voulue, qui correspond à l'identifiant - -- qu'on a envoyé dans cette fonction (part) dans la liste partdata. - - local chunklist = partdata[part] - - for i, v in ipairs(chunklist) do - -- chunklist fonctionne de la même manière que partlist : - -- chaque entrée dans la liste (v) contient deux partie. - -- v[1]: l'identifiant du fichier de chunk où se trouve le chunk voulu - -- v[2]: la liste de chunks voulu. chaque entrée dedans est un nombre, - -- correspondant à un chunk - - --print("- Decompressing group of chunk " .. i .. " located in " .. v[1] .. " (containing " .. #v[2] .. " chunk)") - - for j, w in ipairs(v[2]) do - local chunkfile = v[1] - if (chunkfile == "") or (chunkfile == "self") then - -- si le fichier de chunk est "self", on lui indique que le chunk se trouve - -- dans le même fichier que le fichier de partie. - chunkfile = filename - end - self:addChunk(chunkfile, w) - end - end -end - - -function World:addChunk(filename, chunk) - if filename == "self" then filename = "basic" end - --print("--- Adding chunk id " .. chunk .. " located in " .. filename) - - local chunkfile = require("datas.subgame.sonic-boost.chunks." .. filename) - chunkdata = chunkfile.chunks - - local chunkpos = #self.chunks - - table.insert(self.chunks, chunkdata[chunk]) - self:addEntitiesFromChunk(chunkpos) - self:addRailsFromChunk(chunkpos) - self:updateSize() -end - ----------- ASSETS LOADING FUNCTIONS ---------- - -function World:loadAssets() - self.textures = {} - local folder = "assets/backgrounds/sideview/" - self.textures.tiles = love.graphics.newImage(folder .. "normaltile.png") - self.textures.sptiles = love.graphics.newImage(folder .. "specialtile.png") - self.textures.borders = love.graphics.newImage(folder .. "borders.png") - - self.textures.rail = love.graphics.newImage(folder .. "rails/basic.png") - - self.quads = {} - self.quads.tiles = {} - self.quads.sptiles = {} - self.quads.rails = {} - - local tileline = self.controller.datas.tiles or 0 - local borderline = self.controller.datas.borders or 0 - - - local w, h = self.textures.tiles:getDimensions() - self.quads.tiles[1] = love.graphics.newQuad( 0, tileline*24, 40, 24, w, h) - self.quads.tiles[2] = love.graphics.newQuad(40, tileline*24, 40, 24, w, h) - - local w, h = self.textures.sptiles:getDimensions() - local h2 = math.floor(h / 26) - for i=1, h2 do - self.quads.sptiles[i] = love.graphics.newQuad(0, (i-1)*26, 40, 26, w, h) - end - - local w, h = self.textures.borders:getDimensions() - self.quads.borders = love.graphics.newQuad(0, borderline*10, 80, 10, w, h) - - local w, h = self.textures.rail:getDimensions() - for i=1, 3 do - self.quads.rails[i] = love.graphics.newQuad((i-1)*31, 0, 31, 8, w, h) - end -end - ----------- DATA FUNCTIONS ---------- - -function World:getChunkData(chunkid, turn) - local turn = turn or 1 - local currentTurn, maxTurn = turn, self.controller.missiondata.turns - - if chunkid <= 0 then - if currentTurn <= 1 then - return self:getFakeChunk() - else - chunkid = (chunkid - 1) - chunkid = chunkid % #self.chunks - return self.chunks[chunkid + 1], true - end - elseif chunkid > #self.chunks then - if currentTurn >= maxTurn then - return self:getFakeChunk() - else - chunkid = (chunkid - 1) - chunkid = chunkid % #self.chunks - return self.chunks[chunkid + 1], true - end - else - return self.chunks[chunkid], true - end - -end - -function World:getFakeChunk() - local fakedata = {} - local emptyline = {00, 00, 00, 00, 00, 00, 00, 00} - fakedata.objects = {emptyline, emptyline, emptyline, emptyline, emptyline} - fakedata.terrain = {emptyline, emptyline, emptyline, emptyline, emptyline} - fakedata.grind = {emptyline, emptyline, emptyline, emptyline, emptyline} - - return fakedata, false -end - -function World:getTerrainAtPoint(x, y, turn) - local chunkid = self:getChunkAtPoint(x, y) - local chunkdata, isTrue = self:getChunkData(chunkid, turn) - - local i = math.floor(y / 20) + 1 - local j = math.floor((x % (8*31)) / 31) + 1 - - local terrain = chunkdata.terrain[i][j] - - --print(terrain) - return terrain -end - -function World:getGrindAtPoint(x, y, turn) - local chunkid = self:getChunkAtPoint(x, y) - local chunkdata, isTrue = self:getChunkData(chunkid, turn) - - local i = math.floor(y / 20) + 1 - local j = math.floor((x % (8*31)) / 31) + 1 - - local grind = chunkdata.grind[i][j] - - --print(terrain) - return grind > 0 -end - -function World:getChunkAtPoint(x, y) - return math.floor(x / (8*31)) + 1 -end - - ----------- USEFULL FUNCTIONS ---------- - -function World:updateSize() - self.size = #self.chunks * 8 - self.width = self.size * 31 -end - -function World:getZSortedItems() - local bump2d = require 'libs.bump' - local tsort = require 'libs.tsort' - local world2d = bump2d.newWorld() - - local world = self.entities - - for _, item in ipairs(world:getItems()) do - if item.invisible ~= true and item.destroyed ~= true then - local x,y,z,w,h,d = world:getCube(item) - if world2d:hasItem(item) then - world2d:update(item, x, y + z) - else - world2d:add(item, x, y + z, w, h + d) - end - end - end - - local graph = tsort.new() - local noOverlap = {} - - -- Iterate through all visible items, and calculate ordering of all pairs - -- of overlapping items. - -- TODO: Each pair is calculated twice currently. Maybe this is slow? - for _, itemA in ipairs(world2d:getItems()) do repeat - local x, y, w, h = world2d:getRect(itemA) - local otherItemsFilter = function(other) return other ~= itemA end - local overlapping, len = world2d:queryRect(x, y, w, h, otherItemsFilter) - - if len == 0 then - table.insert(noOverlap, itemA) - - break - end - - local _, aY, aZ, _, aH, aD = world:getCube(itemA) - aDepth = itemA.depth - aID = itemA.id - aType = itemA.type - - --print("testing overlap with itemA " .. aID .. " (" .. aType .. ")") - - - for _, itemB in ipairs(overlapping) do - local _, bY, bZ, _, bH, bD = world:getCube(itemB) - bDepth = itemB.depth - bID = itemB.id - bType = itemB.type - - --print("itemB " .. aID .. " overlap with item " .. bID .. " (" .. bType .. ")") - - if aZ + aD <= bZ then - -- item A is completely above item B - graph:add(itemB, itemA) - --print("itemA is completely above itemB") - elseif bZ + bD <= aZ then - -- item B is completely above item A - graph:add(itemA, itemB) - --print("itemB is completely above itemA") - elseif aY + aH <= bY then - -- item A is completely behind item B - graph:add(itemA, itemB) - --print("itemA is completely behind itemB") - elseif bY + bH <= aY then - -- item B is completely behind item A - graph:add(itemB, itemA) - --print("itemB is completely behind itemA") - elseif aY + aZ + aH + aD == bY + bZ + bH + bD then - -- item A's forward-most point is the same than item B's forward-most point - --print("itemA's forward-most point is the same than itemB's forward-most point") - if aDepth > bDepth then - graph:add(itemB, itemA) - elseif aDepth < bDepth then - graph:add(itemA, itemB) - else - if aID > bID then - graph:add(itemA, itemB) - elseif aID < bID then - graph:add(itemB, itemA) - else - err("two object can't have the same ID") - end - end - elseif aY + aZ + aH + aD >= bY + bZ + bH + bD then - -- item A's forward-most point is in front of item B's forward-most point - graph:add(itemB, itemA) - --print("itemA's forward-most point is in front of itemB's forward-most point") - else - -- item B's forward-most point is in front of item A's forward-most point - graph:add(itemA, itemB) - --print("itemB's forward-most point is in front of itemA's forward-most point") - end - end - until true end - - local sorted, err = graph:sort() - if err then - error(err) - end - for _, item in ipairs(noOverlap) do - table.insert(sorted, item) - end - - return sorted - -end - -function sortItemsToDraw(a, b) - return a.y < b.y -end - -return World diff --git a/sonic-bluestreak.love/scenes/subgame/sonic-boost/init.lua b/sonic-bluestreak.love/scenes/subgame/sonic-boost/init.lua deleted file mode 100644 index a81ca58..0000000 --- a/sonic-bluestreak.love/scenes/subgame/sonic-boost/init.lua +++ /dev/null @@ -1,174 +0,0 @@ -local Scene = require "core.modules.scenes" -local BoostLevel = Scene:extend() - -local folder = "scenes.subgame.sonic-boost.controller." - -local HUD = require(folder .. "hud") -local Background = require(folder .. "background") -local Camera = require(folder .. "camera") -local World = require(folder .. "world") -local PauseMenu = require(folder .. "pause") - -local CharacterManager = require(folder .. "characters") - -local zoneDatas = require "datas.subgame.sonic-boost.levels.zones" - -local LoadAssets = require(folder .. "loader") - -function BoostLevel:new() - BoostLevel.super.new(self) - self:initMission() - - LoadAssets(self) - - self:initManagers() - - self:resetFont() - - self.levelid = nil - self.character = nil - - if self.datas.music ~= nil then - local filepath = "assets/music/" .. self.datas.music .. ".mp3" - print(filepath) - self.assets:setMusic(filepath) - self.assets:playMusic() - end - - self.initiated = false - - self.world:loadWorld() - - self.characters:newPlayer("sonic", 2) - --self.characters:newDummy("sonic", 0) - --self.characters:newDummy("sonic", 1) - --self.characters:newDummy("sonic", 3) - --self.characters:newDummy("sonic", 4) - - if self.areInputsLocked == nil then - self.areInputsLocked = false - end - - self:register() -end - -function BoostLevel:initManagers() - --self.loader = Loader() - self.world = World(self) - self.hud = HUD(self) - self.camera = Camera(self, 0, 0) - self.background = Background(self) - self.characters = CharacterManager(self) - - PauseMenu(self) -end - -function BoostLevel:initMission(levelid) - self:getLevelData(levelid) - - self.mission = {} - self.mission.timer = 0 - self.mission.completed = false -end - -function BoostLevel:startMission() - self.initiated = true -end - -function BoostLevel:getLevelData(file) - local file = file or "testlevel.test1" - local level = require("datas.subgame.sonic-boost.levels." .. file) - - self.zone = level.datas.zone - - local zone_data = zoneDatas[self.zone] - local bypass_data = level.datas.bypass_data - - self.datas = {} - - if (level.datas.bypass_zone) then - self.datas.name = bypass_data.name or zone_data.name - self.datas.borders = bypass_data.borders or zone_data.borders - self.datas.tiles = bypass_data.tiles or zone_data.tiles - self.datas.background = bypass_data.background or zone_data.background - self.datas.music = bypass_data.music or zone_data.music - else - self.datas = zone_data - end - - self.layout = level.layout - self.parts = level.parts - self.endless_parts = level.endless_parts - - self.missiondata = level.datas.missiondata - -end - -function BoostLevel:update(dt) - if self.menusystem.menus["pauseMenu"].isActive == false then - self.assets:update(dt) - self.mission.timer = self.mission.timer + dt - self.world:update(dt) - self.camera:update(dt) - end - - local keys = self:getKeys(1); - - if keys["start"].isPressed then - if not (self.menusystem.menus["pauseMenu"].isActive) then - self.menusystem.menus["pauseMenu"].isActive = true - self.menusystem.menus["pauseMenu"].isVisible = true - self.menusystem.menus["pauseMenu"]:getFocus() - self.assets.isActive = false - else - self.menusystem.menus["pauseMenu"].isActive = false - self.menusystem.menus["pauseMenu"].isVisible = false - self.assets.isActive = true - end - end -end - -function BoostLevel:lockInputs() - self.areInputsLocked = true -end - -function BoostLevel:draw() - self.background:draw() - - self.camera.view:attach() - self.world:draw() - self.camera.view:detach() - - utils.graphics.resetColor() - self.hud:draw() -end - -function BoostLevel:resetFont() - self.assets.fonts["text"]:set() -end - -function BoostLevel:restartLevel() - self:new(self.levelid, self.character) -end - -function BoostLevel:exitLevel() - scenes.title() -end - -function BoostLevel:leave() - self.world:destroy() - - - self.world = nil - self.hud = nil - self.camera = nil - self.background = nil - self.characters = nil - --self.pausemenu = nil - - self.assets:clear() - - collectgarbage() -end - -return BoostLevel diff --git a/sonic-bluestreak.love/scenes/subgames/testBattle/init.lua b/sonic-bluestreak.love/scenes/subgames/testBattle/init.lua new file mode 100644 index 0000000..6f783fd --- /dev/null +++ b/sonic-bluestreak.love/scenes/subgames/testBattle/init.lua @@ -0,0 +1,38 @@ +-- scenes/moveplayer3D :: a basic player movement example in fake3D + +--[[ + Copyright © 2019 Kazhnuz + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local PlayStyle = require "game.modules.subgames" +local MovePlayer = PlayStyle:extend() + +local BattleWorld = require "game.modules.subgames.world.battle" + +function MovePlayer:new(map) + self.map = map + MovePlayer.super.new(self, {"shoot", "test", "battle"}, "testmissions", {"sonic"}) +end + +function MovePlayer:initWorld() + BattleWorld(self, self.map) +end + +return MovePlayer diff --git a/sonic-bluestreak.love/scenes/test_scene/init.lua b/sonic-bluestreak.love/scenes/subgames/testShoot/init.lua similarity index 82% rename from sonic-bluestreak.love/scenes/test_scene/init.lua rename to sonic-bluestreak.love/scenes/subgames/testShoot/init.lua index 236860c..2fdc472 100644 --- a/sonic-bluestreak.love/scenes/test_scene/init.lua +++ b/sonic-bluestreak.love/scenes/subgames/testShoot/init.lua @@ -21,21 +21,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -local PlayStyle = require "game.modules.playstyle" +local PlayStyle = require "game.modules.subgames" local MovePlayer = PlayStyle:extend() -local TestWorld = require "game.modules.world.parent" -local ShootWorld = require "game.modules.world.shoot" -local BattleWorld = require "game.modules.world.battle" +local ShootWorld = require "game.modules.subgames.world.shoot" -function MovePlayer:new() +function MovePlayer:new(map) + self.map = map MovePlayer.super.new(self, {"shoot", "test", "battle"}, "testmissions", {"sonic"}) end function MovePlayer:initWorld() ShootWorld(self, "testlevel.test1") - --BattleWorld(self, "ebeach") - --TestWorld(self) end return MovePlayer diff --git a/sonic-bluestreak.love/scenes/test_scene/assets.lua b/sonic-bluestreak.love/scenes/test_scene/assets.lua deleted file mode 100644 index 9394316..0000000 --- a/sonic-bluestreak.love/scenes/test_scene/assets.lua +++ /dev/null @@ -1,5 +0,0 @@ -return { - ["sprites"] = { - {"sonic", "assets/sprites/characters/sonic"} - } -} diff --git a/sonic-bluestreak.love/scenes/titlescreen/background.lua b/sonic-bluestreak.love/scenes/titlescreen/background.lua deleted file mode 100644 index 7dcb1fd..0000000 --- a/sonic-bluestreak.love/scenes/titlescreen/background.lua +++ /dev/null @@ -1,122 +0,0 @@ -local Background = Object:extend() - -local zoneList = require("datas.gamedata.maps.shoot.zones") - -function Background:new() - self.x1 = 0 - self.x2 = 0 - self.x3 = 0 - self.y = 14 - - local randomZoneList = {} - for k,v in pairs(zoneList) do - table.insert(randomZoneList, k) - end - local id = math.ceil(love.math.random() * #randomZoneList) - self.zone = randomZoneList[id] - print(self.zone) - self:initRessources() -end - -function Background:initRessources() - self.textureId = zoneList[self.zone].tiles - self.background = zoneList[self.zone].background - - self.texture = {} - self.texture.floor = self:generateFloor(self.textureId) - self.texture.border = love.graphics.newImage("assets/backgrounds/borders.png") - self.quads = {} - local w, h = self.texture.border:getDimensions() - self.quads.borders = love.graphics.newQuad(0, self.textureId*10, 80, 10, w, h) - self:addParallax(self.background) -end - -function Background:generateFloor(tile) - local canvas = love.graphics.newCanvas(31*16, 100) - local tile = tile or 1 - - local tileTexture = love.graphics.newImage("assets/backgrounds/normaltile.png") - local tileQuad = {} - local w, h = tileTexture:getDimensions() - tileQuad[1] = love.graphics.newQuad( 0, tile*24, 40, 24, w, h) - tileQuad[2] = love.graphics.newQuad(40, tile*24, 40, 24, w, h) - - love.graphics.setCanvas( canvas ) - - for i=1, 5 do - for j=0, 18 do - local tiley = (i-1)*20 - 4 - local tilex = (j-2)*31 + (i-1)*10 - local variant = 1 + ((i + j) % 2) - love.graphics.draw(tileTexture, tileQuad[variant], tilex, tiley) - end - end - - love.graphics.setCanvas( ) - - local imagedata = canvas:newImageData() - local texture = love.graphics.newImage( imagedata ) - imagedata:release() - canvas:release() - return texture -end - -function Background:addParallax(filename) - local filename = filename or "forest" - local backfolder = "assets/backgrounds/parallax/" - filename = backfolder .. filename - self.texture.back1 = love.graphics.newImage(filename .. "-back.png") - self.texture.back2 = love.graphics.newImage(filename .. "-fore.png") -end - -function Background:update(dt) - local w, h = core.screen:getDimensions() - self.x1 = (self.x1 + 10*dt) - self.x2 = (self.x2 + 20*dt) - self.x3 = (self.x3 + 30*dt) -end - -function Background:draw() - self:drawTiled(self.texture.back1, self.x1, 0, false) - self:drawTiled(self.texture.back2, self.x2, 95, true) - self:drawQuadTiled(self.texture.border, self.quads.borders, self.x3, 95, false) - self:drawTiled(self.texture.floor, self.x3, 105, false) - self:drawQuadTiled(self.texture.border, self.quads.borders, self.x3, 205, false) - -end - -function Background:drawTiled(drawable, x, y, fromBottom) - local w, h = drawable:getDimensions() - local screewn, _ = core.screen:getDimensions() - local x = math.floor(x % w) - - local fromBottom = fromBottom or false - local oy = 0 - if (fromBottom) then - oy = h - end - - local imax = math.ceil(screewn / w) + 1 - for i=0, imax do - love.graphics.draw(drawable, (i*w) - x, self.y + y, 0, 1, 1, 0, oy) - end -end - -function Background:drawQuadTiled(drawable, quad, x, y, fromBottom) - local w, h = drawable:getDimensions() - local screewn, _ = core.screen:getDimensions() - local x = math.floor(x % w) - - local fromBottom = fromBottom or false - local oy = 0 - if (fromBottom) then - local oy = h - end - - local imax = math.ceil(screewn / w) + 1 - for i=0, imax do - love.graphics.draw(drawable, quad, (i*w) - x, self.y + y, 0, 1, 1, 0, oy) - end -end - -return Background diff --git a/sonic-bluestreak.love/scenes/titlescreen/init.lua b/sonic-bluestreak.love/scenes/titlescreen/init.lua deleted file mode 100644 index e0ff070..0000000 --- a/sonic-bluestreak.love/scenes/titlescreen/init.lua +++ /dev/null @@ -1,98 +0,0 @@ --- scenes/test :: a basic test scene - ---[[ - Copyright © 2019 Kazhnuz - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -]] - -local Scene = require "core.modules.scenes" -local TitleScreen = Scene:extend() -local gui = require "game.modules.gui" - -local TweenManager = require "game.modules.tweenmanager" -local Background = require "scenes.titlescreen.background" - -function TitleScreen:new() - TitleScreen.super.new(self) - - self.borders = gui.newBorder(424, 30, 8) - self.assets:addImage("sonic", "assets/artworks/titlescreen_sonic.png") - self.assets:addImage("logo", "assets/artworks/logo.png") - self.assets:addImageFont("menu", "assets/gui/fonts/SA2font") - - self.tweens = TweenManager(self) - self.background = Background(self) - - self.borderY = 0 - self.logoX = 270 - self.sonicX = -180 - - self.darkenOpacity = 1 - self.flashOpacity = 0 - self.canShowPressStart = false - self.showPressStart = true - self.showPressStartTimer = 0.5 - - self.tweens:newTween(0.2, 0.5, {borderY = 30}, "inOutQuart") - self.tweens:newTween(0.5, 0.4, {darkenOpacity = 0}, "outExpo") - self.tweens:newTween(0.7, 0.6, {logoX = 0}, "inOutQuart") - self.tweens:newTween(0.7, 0.6, {sonicX = 0}, "inOutQuart") - self.tweens:newTween(1.3, 0.03, {flashOpacity = 1}, "inQuart") - self.tweens:newTween(1.45, 0.2, {flashOpacity = 0}, "outExpo") - self.tweens:newSwitch(1.4, { "canShowPressStart" }) - self:register() -end - -function TitleScreen:update(dt) - self.tweens:update(dt) - self.background:update(dt) - if (self.canShowPressStart) then - self.showPressStartTimer = self.showPressStartTimer - dt - if self.showPressStartTimer < 0 then - self.showPressStart = (self.showPressStart == false) - self.showPressStartTimer = 0.5 - end - end -end - -function TitleScreen:draw() - utils.graphics.resetColor() - self.background:draw() - - love.graphics.setColor(0, 0, 0, self.darkenOpacity) - love.graphics.rectangle("fill", 0, 0, 424, 240) - utils.graphics.resetColor( ) - - love.graphics.draw(self.borders, 0, self.borderY, 0, 1, -1) - love.graphics.draw(self.borders, 424, 240 - self.borderY, 0, -1, 1) - - self.assets:drawImage("sonic", 90 + self.sonicX, 128, 0, 1, 1, 92, 106) - self.assets:drawImage("logo", 290 + self.logoX, 60, 0, 1, 1, 150, 71) - - if (self.canShowPressStart) and (self.showPressStart) then - local w = self.assets.fonts["menu"]:getWidth("PRESS START") - self.assets.fonts["menu"]:print("PRESS START", 424/1.5, 240/1.5, "center", 0, 1, 1) - end - - love.graphics.setColor(1, 1, 1, self.flashOpacity) - love.graphics.rectangle("fill", 0, 0, 424, 240) - utils.graphics.resetColor( ) -end - -return TitleScreen