commit 87e4b0cc4b5cab48a90b1db3fccf6b4ccebea883 Author: Madiwka3 Date: Sun Apr 18 20:45:38 2021 +0600 First commit diff --git a/buttonClutter.lua b/buttonClutter.lua new file mode 100644 index 0000000..b9ed52e --- /dev/null +++ b/buttonClutter.lua @@ -0,0 +1,16 @@ +function buttonClutter() + table.insert(buttons, menu:addButton("Practice", + function() + gameState = "practice" + end)) + table.insert(buttons, menu:addButton("Levels", + function() + gameState = "selectlv" + end +)) +end +local t=0 +function explode(x, y) + t = t+10 + love.graphics.circle("fill", x, y, t) +end \ No newline at end of file diff --git a/debuggame.sh b/debuggame.sh new file mode 100755 index 0000000..9ff32cd --- /dev/null +++ b/debuggame.sh @@ -0,0 +1,6 @@ +rm game.love +rm game.zip +zip -r game * +mv game.zip game.love +love game.love +rm game.love \ No newline at end of file diff --git a/entities/background.jpg b/entities/background.jpg new file mode 100644 index 0000000..f22ccf1 Binary files /dev/null and b/entities/background.jpg differ diff --git a/entities/base/base.lua b/entities/base/base.lua new file mode 100644 index 0000000..8ed70f1 --- /dev/null +++ b/entities/base/base.lua @@ -0,0 +1,22 @@ +base = Class{} + +G = 6.67e-5 + +function base:init(x, y) +self.x = x +self.y = y +self.image = love.graphics.newImage("entities/base/base.png") +self.w = self.image:getWidth() +self.h = self.image:getHeight() +end + +function base:update(dt) + local distanceToShip = math.sqrt((firstShip.x - self.x)^2 + (firstShip.y - self.y)^2) + if distanceToShip < self.w/2 then + reachedGoal = true + end +end + +function base:draw() + love.graphics.draw(self.image, self.x, self.y, 0, 1, 1, self.w/2, self.w/2) +end \ No newline at end of file diff --git a/entities/base/base.png b/entities/base/base.png new file mode 100644 index 0000000..b4e71ad Binary files /dev/null and b/entities/base/base.png differ diff --git a/entities/camera/VCAM.lua b/entities/camera/VCAM.lua new file mode 100644 index 0000000..966dbb1 --- /dev/null +++ b/entities/camera/VCAM.lua @@ -0,0 +1,11 @@ +VCAM = Class{} + +function VCAM:init(x, y) +self.x = x +self.y = y +end + +function VCAM:update(x,y) +self.x = x +self.y = y +end \ No newline at end of file diff --git a/entities/planet/planet.lua b/entities/planet/planet.lua new file mode 100644 index 0000000..f7e71ed --- /dev/null +++ b/entities/planet/planet.lua @@ -0,0 +1,45 @@ +planet = Class{} + +G = 6.67e-5 + +function planet:init(x, y, mass, radius, img) +self.x = x +self.y = y +self.mass = mass +self.r = radius +self.w = img:getWidth() +self.image = img +self.angle = 0 +self.color = {1,1,1,1} +end + +function planet:update(dt) + local distanceToShip = math.sqrt((firstShip.x - self.x)^2 + (firstShip.y - self.y)^2) + + local gravitationalAttraction = G*self.mass/(distanceToShip^2) + print((firstShip.x - self.x) .. " " .. (firstShip.y - self.y)) + self.angle = math.atan( (firstShip.y - self.y)/ (firstShip.x - self.x)) + if self.x < firstShip.x then + self.angle = self.angle - 3.14159 + end + --print("Angle is:" .. self.angle*57.29) + self.attractionY = math.sin(self.angle) * gravitationalAttraction + self.attractionX = math.cos(self.angle) * gravitationalAttraction + love.window.setTitle(self.attractionX) + firstShip.dx = firstShip.dx + self.attractionX + firstShip.dy = firstShip.dy + self.attractionY + if distanceToShip < self.w/4 then + shipIsHit = true + end +end + +function planet:draw() + --love.graphics.rectangle("fill", firstShip.x, firstShip.y, 30, 30) + love.graphics.push() + love.graphics.translate(firstShip.x, firstShip.y) -- move relative (0,0) to (x,y) + love.graphics.rotate(self.angle) -- rotate coordinate system around relative (0,0) (absolute (x,y)) + --love.graphics.rectangle("fill", -(firstShip.x - self.x)/2, -20/2, (firstShip.x - self.x), 20) VECTOR + love.graphics.pop() + love.graphics.setColor(unpack(self.color)) + love.graphics.draw(self.image, self.x, self.y, 1.5708, self.r, self.r, self.w/2, self.w/2) +end \ No newline at end of file diff --git a/entities/planet/planet1.png b/entities/planet/planet1.png new file mode 100644 index 0000000..41cd97d Binary files /dev/null and b/entities/planet/planet1.png differ diff --git a/entities/planet/planet10.png b/entities/planet/planet10.png new file mode 100644 index 0000000..c8ba6c8 Binary files /dev/null and b/entities/planet/planet10.png differ diff --git a/entities/planet/planet11.png b/entities/planet/planet11.png new file mode 100644 index 0000000..24dc1d8 Binary files /dev/null and b/entities/planet/planet11.png differ diff --git a/entities/planet/planet12.png b/entities/planet/planet12.png new file mode 100644 index 0000000..e81d38e Binary files /dev/null and b/entities/planet/planet12.png differ diff --git a/entities/planet/planet13.png b/entities/planet/planet13.png new file mode 100644 index 0000000..a2aaf34 Binary files /dev/null and b/entities/planet/planet13.png differ diff --git a/entities/planet/planet14.png b/entities/planet/planet14.png new file mode 100644 index 0000000..ce13954 Binary files /dev/null and b/entities/planet/planet14.png differ diff --git a/entities/planet/planet15.png b/entities/planet/planet15.png new file mode 100644 index 0000000..9d6dfc7 Binary files /dev/null and b/entities/planet/planet15.png differ diff --git a/entities/planet/planet16.png b/entities/planet/planet16.png new file mode 100644 index 0000000..f080112 Binary files /dev/null and b/entities/planet/planet16.png differ diff --git a/entities/planet/planet17.png b/entities/planet/planet17.png new file mode 100644 index 0000000..4a51251 Binary files /dev/null and b/entities/planet/planet17.png differ diff --git a/entities/planet/planet18.png b/entities/planet/planet18.png new file mode 100644 index 0000000..d441182 Binary files /dev/null and b/entities/planet/planet18.png differ diff --git a/entities/planet/planet2.png b/entities/planet/planet2.png new file mode 100644 index 0000000..f1c7c96 Binary files /dev/null and b/entities/planet/planet2.png differ diff --git a/entities/planet/planet3.png b/entities/planet/planet3.png new file mode 100644 index 0000000..60cc640 Binary files /dev/null and b/entities/planet/planet3.png differ diff --git a/entities/planet/planet4.png b/entities/planet/planet4.png new file mode 100644 index 0000000..71ca79a Binary files /dev/null and b/entities/planet/planet4.png differ diff --git a/entities/planet/planet5.png b/entities/planet/planet5.png new file mode 100644 index 0000000..4cd931e Binary files /dev/null and b/entities/planet/planet5.png differ diff --git a/entities/planet/planet6.png b/entities/planet/planet6.png new file mode 100644 index 0000000..adc1d89 Binary files /dev/null and b/entities/planet/planet6.png differ diff --git a/entities/planet/planet7.png b/entities/planet/planet7.png new file mode 100644 index 0000000..e06bcf3 Binary files /dev/null and b/entities/planet/planet7.png differ diff --git a/entities/planet/planet8.png b/entities/planet/planet8.png new file mode 100644 index 0000000..2fe301d Binary files /dev/null and b/entities/planet/planet8.png differ diff --git a/entities/planet/planet9.png b/entities/planet/planet9.png new file mode 100644 index 0000000..d98c385 Binary files /dev/null and b/entities/planet/planet9.png differ diff --git a/entities/ship/large_red_01.png b/entities/ship/large_red_01.png new file mode 100644 index 0000000..9837352 Binary files /dev/null and b/entities/ship/large_red_01.png differ diff --git a/entities/ship/ship.lua b/entities/ship/ship.lua new file mode 100644 index 0000000..9f0a01d --- /dev/null +++ b/entities/ship/ship.lua @@ -0,0 +1,103 @@ +ship = Class{} + + +function ship:init(x, y, image) +self.x = x +self.y = y +self.ox = x +self.oy = y +self.dy = 0 +self.dx = 5 +self.image = love.graphics.newImage(image) +self.width = self.image:getWidth() +self.height = self.image:getHeight() +self.rotation = 1.5708 +self.vector = 1.5708 +self.color = {1,1,1,1} +self.path = {} +end +function ship:newPathDot(dotx, doty) + return { + x = dotx, + y = doty + } +end +function ship:update(dt) + if not shipIsHit then + table.insert(self.path, self:newPathDot(self.x, self.y)) + self.x = self.x + self.dx/2 + self.y = self.y + self.dy/2 + if self.dx ~= 0 then + self.vector = math.atan( self.dy/ self.dx) + end + if love.keyboard.isDown('s') then + self.speed = math.sqrt(self.dx^2 + self.dy^2) + self.speed = self.speed - 0.5 + self.dx = math.cos(self.vector) * self.speed + self.dy = math.sin(self.vector) * self.speed + end + if love.keyboard.isDown('w') then + self.speed = math.sqrt(self.dx^2 + self.dy^2) + self.speed = self.speed + 0.5 + self.dx = math.cos(self.vector) * self.speed + self.dy = math.sin(self.vector) * self.speed + end + if love.keyboard.isDown('left') then + self.dx = self.dx - 0.5 + end + if love.keyboard.isDown('right') then + self.dx = self.dx + 0.5 + end + if love.keyboard.isDown('up') then + self.dy = self.dy - 0.5 + end + if love.keyboard.isDown('down') then + self.dy = self.dy + 0.5 + end + print(self.speed) + + --[[ + if love.keyboard.isDown('right') then + self.rotation = self.rotation + 10 + elseif love.keyboard.isDown('left') then + self.rotation = self.rotation - 10 + end]]-- + + print("rotation:" .. self.rotation) + print("speed:" .. self.dx .. " " .. self.dy) + + if self.dx < 0 then + self.vector = self.vector - 3.14159 + end + self.vector = self.vector + 1.5708 +end +end + +function ship:draw() + + -- Draw the `self.canvas` to screen + love.graphics.setColor(unpack(self.color)) + print("DAW" .. camera.x) + love.graphics.draw(self.image, self.x, self.y, self.vector, 1, 1, self.width/2, self.height/2) + for i in ipairs(self.path) do + if i > 1 then + love.graphics.setColor(0,1,0,1) + print("DOING".. i) + love.graphics.line(self.path[i].x, self.path[i].y, self.path[i-1].x, self.path[i-1].y) + end + end + love.graphics.setColor(1,1,1,1) + +end + +function ship:reset() + self.x = self.ox + self.y = self.oy + self.dy = 0 + self.dx = 20 + self.rotation = 1.57 + self.canvas = love.graphics.newCanvas(WINDOW_WIDTH, WINDOW_HEIGHT) + self.vector = 1.56 + self.speed = 0 + self.path = {} +end diff --git a/entities/ship/smol_red_01.png b/entities/ship/smol_red_01.png new file mode 100644 index 0000000..a950755 Binary files /dev/null and b/entities/ship/smol_red_01.png differ diff --git a/entities/trashbin.png b/entities/trashbin.png new file mode 100644 index 0000000..8beb4a3 Binary files /dev/null and b/entities/trashbin.png differ diff --git a/explosion.lua b/explosion.lua new file mode 100644 index 0000000..2280299 --- /dev/null +++ b/explosion.lua @@ -0,0 +1,27 @@ +explosion = Class{} + +function explosion:init(x, y, v, color) + self.color = color + self.x = x + self.y = y + self.v = v + self.range = 0 + self.killed = false + print(self.i) +end + +function explosion:update(dt) + self.range = self.range + dt * 24 + if self.range * self.v > WINDOW_WIDTH * 2 then + print("killing myself with range" .. self.range) + self.killed = true + end +end + + + +function explosion:render() + print("rendering myself" .. self.x .. " " .. self.y .. " " .. self.range .. " " .. self.v) + love.graphics.setColor(unpack(self.color)) + love.graphics.circle("fill", self.x, self.y, self.range * self.v, 100) +end \ No newline at end of file diff --git a/fakemain.lua b/fakemain.lua new file mode 100644 index 0000000..c134942 --- /dev/null +++ b/fakemain.lua @@ -0,0 +1,2505 @@ +--CALLING OTHER LUA FILES + +love.filesystem.setIdentity( "pong" ) +love.filesystem.createDirectory( "a" ) +require "src/dependencies" + + +--CANCELLED ATTEMPETED SHADING (NOT WORKING) +local shader_code = + [[ +vec4 effect(vec4 color, Image image, vec2 uvs, vec2 screen_coords) { + vec4 pixel = Texel(image,uvs); + return pixel * color; +} +]] +--ANDROID EXLUSIVE VARIABLES +touches = {} +doubleclick1 = false +doubleclick2 = false +hold1 = false +hold2 = false +debug = false +paused = false +androidButtons = {} +pauseButtons = {} +doneButtons = {} +showTouchControls = false +--GLOBAL VARIABLES + + +--0.9 VARIABLES +isButtonAnimated = false + +wallsLoadError = false +background = love.graphics.newImage('img/background.jpg') +backgroundScroll = 0 + +background_scroll_speed = 10 +background_looping_point = 810 + +--END HERE + + + + +frameratecap = 1/60 +realtimer = 0 +myip = "unknown" +status = "offline" +gameMode = "normal" +ts = 0 +globalState = "menu" +timeIsSlow = false +timeIsSlow2 = false +originalSpeed = 200 +explosionRange = 0 +blockinput = false +wall1width = 30 +nuclearanimation = 3 +easternum = 0 +qq = 0 +ball_DIR = 0 +updaterate = 0.015 +RED = 255 +hitNum = {} +hitNum[1] = 0 +hitNum[2] = 0 +hitNum[3] = 0 +confirmation = "N" +hitNum[4] = 0 +p1bonus = 0 +p2bonus = 0 +hitNum[5] = 0 +hitNum[6] = 0 +GREEN = 255 +IP = '45.76.95.31' +IPnew = '45.76.95.31' +BLUE = 255 +updateTEXT = "Galaxy Update" +maxBalls = 1 +playerCount = 1 +player1reverbav = 0 +playertext = "1v1" +player2reverbav = 0 +elapsed = 0 +rotation = 0 +TEXT = "Nuclear Pong" +currentKey = " " +ptw = 10 +checkrate = 0.5 +--CHECKING IF CONTROLS ARE TAKEN +danger = "none" +danger2 = "none" + +nuckemodactive = 0 +maxspeed = 700 +DIFFERENCE_X = 1 +DIFFERENCE_Y = 1 +OFFSET_X = 0 +OFFSET_Y = 0 +paddle_SPEED = 200 +textamount = 15 +AI_STRIKEMOD = 1000 +resolutionWin = 0 +AGAINST_AI = 0 +RESOLUTION_SET = 0 +AI_NUKEMOD = 1000 +animstart = true +AI_SPEED = 300 +craz = 0 +AI_LEVEL = 500 +isFullscreen = 0 +prtext = "Easy" +lastSentKey = "c" +MAP_TYPE = 0 +lastSentKeyClient = "c" +difficultyl = 300 +req = "pp" +ballSet = 200 +p1control = {up = "a", down = "z", super = "s", counter = "x"} +p2control = {up = ";", down = ".", super = "l", counter = ","} +synctext = "Independent" +synctype = 0 +function newTouch(id, x, y) + return { + id = id, + x = x, + y = y, + originalX = x, + originalY = y + } +end +function newButton(text, fn, sp, qp) + if qp ~= nil then + return { + x = (VIRTUAL_WIDTH * 0.5) - VIRTUAL_WIDTH * (1/3)*0.5, + text = text, + fn = fn, + skipAnim = true, + now = false, + last = false + } + else + return { + x = 1300, + text = text, + fn = fn, + skipAnim = sp, + now = false, + last = false + } +end +end +function love.keyboard.mouseWasReleased() + return love.keyboard.mouseisReleased +end +function autoSave(dt) + autoTimer = autoTimer + dt +end + +function balancer() + if (player2score == 9 or player1score == 9) then + shakeDuration = 5 + if debug then + --print("Shaking set to match almost over") + end + end + if (player1score < player2score) then + p1bonus = (player2score - player1score) * 5 + else + p1bonus = 0 + end + if (player2score < player1score) then + p2bonus = (player1score - player2score) * 5 + else + p2bonus = 0 + end +end + +function newWall(wallx, wally, wallwidth, wallheight) + return { + wallx = wallx, + wally = wally, + walwidth = wallwidth, + wallheight = wallheight + } +end +speedParameters = {} +buttons = {} +IPselect = {} +difbuttons = {} +settings = {} +walls = {} +editorpicks = {} +controlSettings = {} +modeSelectorButtons = {} +pracdiff = {} +playerCountButtons = {} +function controlChanger() + if (gameState == "assign") then + love.graphics.clear(50 / 255, 50 / 255, 50 / 255, 255) + love.graphics.printf("SELECT BUTTON", 0, VIRTUAL_HEIGHT / 2, VIRTUAL_WIDTH, "center") + end +end +function love.load() + walls = {} + + + print (love.filesystem.getSaveDirectory()) + print (love.filesystem.getIdentity( )) + love.graphics.setDefaultFilter('nearest', 'nearest') + love.keyboard.setKeyRepeat(true) + + tick.framerate = 60 + simpleScale.setWindow(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT) + configfile = io.open("config.lua", "r") + configsave = io.open("config.lua", "w") + shader = love.graphics.newShader(shader_code) + time_1 = 0 + --print("Debug active") + --load + + testwalls = love.filesystem.load("save") + if testwalls ~= nil then + walls = love.filesystem.load("save") + print("Save file found") + else + print("No save file found!") + end + + light = 0 + image = love.graphics.newImage("Madi.png") + table.insert( + androidButtons, + newButton( + "H", + function() + if globalState == "base" and gameState ~= "done" then + paused = true + else + resetButtonX(buttons) + TEXT = "Nuclear Pong" + resettinggenius() + paused = false + gameState = "menu" + ball[1].dx = 1 + ball_DIR = 1 + ball[1].dy = 1 + globalState = "menu" + hardmanager() + end + end, + false + ) + ) + table.insert( + editorpicks, + newButton( + "C", + function() + for k in pairs(walls) do + walls[k] = nil + end + end, + false + ) + ) + table.insert( + pauseButtons, + newButton( + "Resume", + function() + paused = false + TEXT = "Let's Continue" + end, + false + ) + ) + table.insert( + doneButtons, + newButton( + "Freeplay", + function() + if player1score > player2score then + gameState = "2serve" + else + gameState = "1serve" + end + potentialnuke1 = 0 + potentialnuke2 = 0 + striken = 0 + if (nuckemodactive == 0) then + areanuclear = 0 + nuclearanimation = 3 + end + potentialstrike1 = 0 + potentialstrike2 = 0 + player1nukescore = 0 + player2nukescore = 0 + end, + false + ) + ) + table.insert( + doneButtons, + newButton( + "Menu", + function() + resettinggenius() + TEXT = "Nuclear Pong" + paused = false + gameState = "menu" + ball[1].dx = 1 + ball_DIR = 1 + ball[1].dy = 1 + globalState = "menu" + hardmanager() + end, + false + ) + ) + if not isAndroid then + table.insert( + pauseButtons, + newButton( + "Toggle Fullscreen", + function() + myscreen:toggle(VIRTUAL_HEIGHT, VIRTUAL_WIDTH) + DIFFERENCE_X = myscreen.c + DIFFERENCE_Y = myscreen.d + OFFSET_X = myscreen.e + OFFSET_Y = myscreen.f + end, + true + ) + ) + end + table.insert( + pauseButtons, + newButton( + "Toggle Music", + function() + if mute then + musicController("mute", 0) + else + musicController("mute", 1) + end + end, + true + ) + ) + table.insert( + pauseButtons, + newButton( + "Menu", + function() + resettinggenius() + paused = false + TEXT = "Nuclear Pong" + gameState = "menu" + ball[1].dx = 1 + ball_DIR = 1 + ball[1].dy = 1 + globalState = "menu" + hardmanager() + end, + false + ) + ) + + table.insert( + editorpicks, + newButton( + "S", + function() + print(love.filesystem.write("save.lua", serialize(walls))) + end, + true + ) + ) + table.insert( + editorpicks, + newButton( + "L", + function() + walls = love.filesystem.load("save.lua")() + if walls == nil then + walls = {} + wallsLoadError = true + end + end, + true + ) + ) + table.insert( + buttons, + newButton( + "Singleplayer", + function() + ptw = 10 + gameState = "gameMode" + end, + false + ) + ) + table.insert( + buttons, + newButton( + "Online", + function() + MAP_TYPE = 0 + if isAndroid then + love.keyboard.setTextInput( true, 0, VIRTUAL_HEIGHT, VIRTUAL_WIDTH, VIRTUAL_HEIGHT/3) + end + gameState = "chooseIP" + end, + false + ) + ) + table.insert( + IPselect, + newButton( + "Host", + function() + globalState = "nettest" + AGAINST_AI = 0 + gameState = "1serve" + ball[1]:reset(1, 1) + end, + true + ) + ) + table.insert( + IPselect, + newButton( + "Guest", + function() + globalState = "clienttest" + AGAINST_AI = 0 + gameState = "1serve" + ball[1]:reset(1, 1) + end, + true + ) + ) + table.insert( + buttons, + newButton( + "Multiplayer", + function() + gameState = "multiMode" + end, + false + ) + ) + if not isAndroid then + table.insert( + buttons, + newButton( + "Settings", + function() + AGAINST_AI = 0 + gameState = "windowsettings" + end, + false + ) + ) + else + table.insert( + buttons, + newButton( + "Show Controls", + function() + if showTouchControls then + showTouchControls = false + else + showTouchControls = true + end + gameState = "touchcontrols" + end, + true + ) + ) + end + table.insert( + buttons, + newButton( + "Exit", + function() + love.event.quit(0) + end, + false + ) + ) + table.insert( + difbuttons, + newButton( + "Easy", + function() + hardmanager("easy") + end, + false + ) + ) + table.insert( + difbuttons, + newButton( + "Normal", + function() + hardmanager("normal") + end, + false + ) + ) + table.insert( + difbuttons, + newButton( + "Hard", + function() + hardmanager("hard") + end, + false + ) + ) + table.insert( + difbuttons, + newButton( + "Smart", + function() + hardmanager("smart") + end, + false + ) + ) + --table.insert( + -- settings, + -- newButton( + -- "Change Map", + -- function() + -- MAP_TYPE = MAP_TYPE + 1 + -- end + -- ) + --) + table.insert( + settings, + newButton( + "Toggle Fullscreen", + function() + myscreen:toggle(VIRTUAL_HEIGHT, VIRTUAL_WIDTH) + DIFFERENCE_X = myscreen.c + DIFFERENCE_Y = myscreen.d + OFFSET_X = myscreen.e + OFFSET_Y = myscreen.f + end, + true + ) + ) + if isAndroid then + table.insert( + buttons, + newButton( + "Toggle Music", + function() + if mute then + musicController("mute", 0) + else + musicController("mute", 1) + end + end, + true + ) + ) + end + table.insert( + settings, + newButton( + "Toggle Music", + function() + if mute then + musicController("mute", 0) + else + musicController("mute", 1) + end + end, + true + ) + ) + table.insert( + settings, + newButton( + "Editor", + function() + gameState = "editor" + end, + true + ) + ) + table.insert( + settings, + newButton( + "Speed Settings", + function() + gameState = "speedSettings" + end, + true + ) + ) + table.insert( + settings, + newButton( + "Control Settings", + function() + gameState = "controlSettings" + end, + false + ) + ) + table.insert( + settings, + newButton( + "Back to Menu", + function() + gameState = "menu" + end, + false + ) + ) + table.insert( + speedParameters, + newButton( + "Back to Menu", + function() + gameState = "windowsettings" + end, + false + ) + ) + --table.insert(speedParameters, newButton("Ball Speed: ", function() speedSetter('ball') end)) + table.insert( + playerCountButtons, + newButton( + "Ball Speed: ", + function() + speedSetter("ball") + end, + true + ) + ) + --table.insert(speedParameters, newButton("snc", function() speedSetter('snc') end)) + table.insert( + playerCountButtons, + newButton( + "snc", + function() + speedSetter("snc") + end, + true + ) + ) + table.insert( + speedParameters, + newButton( + "NUCLEAR MODE", + function() + speedSetter("nuclearmod") + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "1up", + function() + gameState = "assign" + req = "p1up" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "1down", + function() + gameState = "assign" + req = "p1down" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "1special", + function() + gameState = "assign" + req = "p1super" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "1ct", + function() + gameState = "assign" + req = "p1ct" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "2up", + function() + gameState = "assign" + req = "p2up" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "2down", + function() + gameState = "assign" + req = "p2down" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "2special", + function() + gameState = "assign" + req = "p2super" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "2ct", + function() + gameState = "assign" + req = "p2ct" + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "Default", + function() + p1control = {up = "a", down = "z", super = "s", counter = "x"} + p2control = {up = ";", down = ".", super = "l", counter = ","} + end, + true + ) + ) + table.insert( + controlSettings, + newButton( + "Return", + function() + gameState = "windowsettings" + end, + false + ) + ) + table.insert( + modeSelectorButtons, + newButton( + "Nuclear Pong", + function() + gameState = "difficulty" + end, + false + ) + ) + table.insert( + modeSelectorButtons, + newButton( + "Main Menu", + function() + gameState = "menu" + end, + false + ) + ) + table.insert( + pracdiff, + newButton( + "Silverblade", + function() + speedSetter("practice") + end, + false + ) + ) + table.insert( + pracdiff, + newButton( + "Return", + function() + speedSetter("reset") + gameState = "gameMode" + end, + false + ) + ) + table.insert( + pracdiff, + newButton( + "Go!", + function() + gameMode = "practice" + hardmanager("practice") + end, + false + ) + ) + --table.insert(playerCountButtons, newButton("1v1", function() speedSetter('pc') end)) + table.insert( + playerCountButtons, + newButton( + "ballCount", + function() + speedSetter("ballz") + end, + true + ) + ) + table.insert( + difbuttons, + newButton( + "ballCount", + function() + speedSetter("ballz") + end, + true + ) + ) + table.insert( + playerCountButtons, + newButton( + "Return", + function() + speedSetter("reset") + gameState = "menu" + + end, + false + ) + ) + table.insert( + playerCountButtons, + newButton( + "ptw", + function() + speedSetter("ptw") + end, + true + ) + ) + table.insert( + playerCountButtons, + newButton( + "Play", + function() + AGAINST_AI = 0 + gameState = "1serve" + globalState = "base" + end, + false + ) + ) + table.insert( + playerCountButtons, + newButton( + "Reverse Play", + function() + gameState = "1serve" + gameMode = "reversegame" + globalState = "base" + end, + false + ) + ) + + --table.insert(speedParameters, newButton("Ball Speed: ", function() speedSetter() end)) + + love.window.setTitle("NUCLEAR PONG") + textphrases = { + "Amazing", + "Superb", + "Absolutely beautiful!", + "Awesome", + "Look at That!", + "Great", + "Nice", + "Boom!", + "Dangerous!", + "Astonishing!", + "u/ebernerd saved me", + "Absolutely Wonderful!", + "Exsquisite", + "Delicate", + "Pow!", + "Great Hit", + "all hail nazarbayev" + } + sounds = { + ["updateMusic"] = love.audio.newSource("audio/theme1.mp3", "static"), + ["gayTheme"] = love.audio.newSource("audio/theme2.mp3", "static"), + ["gayTheme2"] = love.audio.newSource("audio/theme3.mp3", "static"), + ["gayTheme3"] = love.audio.newSource("audio/theme4.mp3", "static"), + ["gayTheme4"] = love.audio.newSource("audio/theme5.mp3", "static"), + ["beep"] = love.audio.newSource("audio/hit1.mp3", "static"), + ["wallhit"] = love.audio.newSource("audio/hit2.wav", "static"), + ["win"] = love.audio.newSource("win.wav", "static"), + ["score"] = love.audio.newSource("audio/score.wav", "static"), + ["nuke"] = love.audio.newSource("audio/bomb.wav", "static"), + ["striking"] = love.audio.newSource("audio/superhit.wav", "static"), + ["nuclearhit"] = love.audio.newSource("audio/hit1.mp3", "static"), + ["time"] = love.audio.newSource("audio/time.wav", "static") + } + love.graphics.setDefaultFilter("nearest", "nearest") + --comic sans lmao + math.randomseed(os.time()) + smallfont = love.graphics.newFont("font.ttf", 25) + scorefont = love.graphics.newFont("font.ttf", 60) + love.graphics.setFont(smallfont) + + --push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, { + -- fullscreen = isFullscreen, + -- resizable = true, + -- vsync = true, + --}) + love.window.setVSync( 0 ) + player1score = 0 + player2score = 0 + areanuclear = 0 + player1nukescore = 0 + player2nukescore = 0 + striken = 0 + soundtype = 1 + soundturn = 1 + potentialstrike1 = 0 + potentialstrike2 = 0 + potentialnuke1 = 0 + potentialnuke2 = 0 + player1striken = 0 + player2striken = 0 + randomtext = 0 + selecting = 0 + number = 0 + elec = 1 + INDIC = { + "", + "", + "", + "" + } + --playe1nuke + player1 = paddle(0, 30, 10, 100, 1) + player2 = paddle(VIRTUAL_WIDTH * 0.99, VIRTUAL_HEIGHT * 0.88, 10, 100, 2) + player3 = paddle(5000, 5000, 10, 100) + player4 = paddle(5000, 5000, 10, 100) + ball = {} + explosions = {} + ball[1] = eball(VIRTUAL_WIDTH / 2, VIRTUAL_HEIGHT / 2 - 2, 16, 16) + ball[2] = eball(VIRTUAL_WIDTH / 1.9, VIRTUAL_HEIGHT / 2 - 2, 16, 16) + ball[3] = eball(VIRTUAL_WIDTH / 1.8, VIRTUAL_HEIGHT / 2 - 2, 16, 16) + ball[4] = eball(VIRTUAL_WIDTH / 2.2, VIRTUAL_HEIGHT / 2 - 2, 16, 16) + ball[5] = eball(VIRTUAL_WIDTH / 2.1, VIRTUAL_HEIGHT / 2 - 2, 16, 16) + myscreen = fullScreener(RESOLUTION_SET, isFullscreen, DIFFERENCE_X, DIFFERENCE_Y, OFFSET_X, OFFSET_Y) + if isAndroid then + myscreen:toggle(VIRTUAL_HEIGHT, VIRTUAL_WIDTH) + DIFFERENCE_X = myscreen.c + DIFFERENCE_Y = myscreen.d + OFFSET_X = myscreen.e + OFFSET_Y = myscreen.f + end + mymenu = mainMenu() + + ballSpeed = 200 + background_scroll_speed = ballSpeed / 20 + background_scroll_speed = ballSpeed / 20 + ballDX = math.random(2) == 1 and 100 or -100 + ballDY = math.random(-50, 50) + + gameState = "animation" +end +t = 0 +shakeDuration = 0 +shakeMagnitude = 1 +function startShake(duration, magnitude) + t, shakeDuration, shakeMagnitude = 0, duration or 1, magnitude or 5 +end +function displayFPS() + love.window.setTitle(love.timer.getFPS()) + --love.window.setTitle(globalState .. " " .. gameState .. " " .. paddle_SPEED .. " " .. p1bonus .. " " .. player1.dy) + if love.keyboard.isDown("space") then + player1nukescore = 200 + player1score = player1score + 0.2 + player2nukescore = 200 + end + +end + +function speedControl() + if (ballSpeed > maxspeed and gameState == "play") then + ballSpeed = maxspeed + background_scroll_speed = ballSpeed / 20 + end +end +checking = 0 +function love.update(dt) + --checking = checking + 1 + --print(checking) + --print("IMPORTANT!!!!!" .. globalState .. gameState) + for i, explosion in ipairs(explosions) do + explosion:update(dt) + end + staticanimatorcounter(dt) + player1.goal = -1 + player2.goal = -1 + if gameState == "chooseIP" then + checkCurrentServer(dt) + end + if debug then + displayFPS() + --print(player2.y .. " " .. player2.goal .. " " .. player2.dy .. " " .. AI_SPEED .. " " .. paddle_SPEED .. " " .. lastSentKeyClient) + end + if globalState == "base" and not paused then + basegame(dt) + + end + if globalState == "menu" then + debugCheck(dt) + if gameState ~= "animation" then + menuDemo(dt) + end + end + if gameState ~= "animation" then + musicController('norm', 1) + + end + + if globalState == "nettest" then + --print("Confcode: " .. confirmation) + if confirmation == "N" then + basegame(dt) + end + nettest(dt) + + end + if globalState == "selfhost" then + --print("Confcode: " .. confirmation) + if confirmation == "N" then + globalState = "nettest" + basegame(dt) + end + globalState = "selfhost" + selfHost(dt) + IP = "127.0.0.1" + + end + if globalState == "clienttest" then + ts = ts + dt + if confirmation == "N" then + lastSentKeyP1 = lastSentKeyClient + clientsBaseGame(dt) + end + clienttest(dt) + end + +end +serverinit = false +dserverinit = false +datawaspassedtimer = 0 +clientinit = false +function love.textinput(t) + if gameState == "chooseIP" then + IPnew = IPnew .. t + end +end +function nettest(dt) + --print("nettest running") + if serverinit == false then + local socket = require "socket" + local address, port = IP, 12345 + --print(address) + udp = socket.udp() + udp:setpeername(address, port) + udp:settimeout(0) + serverinit = true + end + if isAndroid then + if table.empty(touches) then + lastSentKey = "g" + end + end + for i = 1, maxBalls do + ts = ts + dt + if ts > updaterate then + udp:send(tostring(lastSentKey) .. + '|' .. tostring(ball[1].dy) .. + '|' .. tostring(player2.y) .. + '|' .. tostring(player1.y) .. + '|' .. tostring(player1score) .. + '|' .. tostring(player2score) .. + '|' .. tostring(player1nukescore) .. + '|' .. tostring(player2nukescore) .. + '|' .. tostring(ball[1].x) .. + '|' .. tostring(ball[1].y) .. + '|' .. gameState .. + '|' .. tostring(ball[1].dx) .. + '|' .. tostring(ballSpeed) .. + '|' .. tostring(paddle_SPEED) .. + '|' .. tostring(player1striken) .. + '|' .. tostring(areanuclear) .. + "|HOST") + ts = 0 + end + end + + local data + local datanumtest = 0 + local datawaspassed = false + repeat + datanumtest = datanumtest + 1 + --print("LATENCY: " .. tostring(datanumtest)) + data = udp:receive() + if data then + datawaspassed = true + --print("ReceivedINFO: " .. data) + confirmation = "N" + local p = split(data, '|') + if p[17] then + if tonumber(p[18]) > 90 then + confirmation = "L" + end + if p[17] ~= "CLIENT" then + confirmation = "U" + end + elseif p[1] == "RESPONSE" then + if p[2] == "1" then + + elseif p[2] == "2" then + + elseif p[2] == "3" then + end + else + confirmation = "U" + end + + if p[17] then + if ball[1].disabled and ball[1].x > 20 and ball[1].x < VIRTUAL_WIDTH - 20 then + ball[1].disabled = false + --print("illegal disabling") + end + if gameState ~= "1serve" then + if (ball[1].x > VIRTUAL_WIDTH/2) then + if tonumber(p[9]) > VIRTUAL_WIDTH/2 then + die = tonumber(p[2]) + lastSentKeyClient, + ball[1].dy, + player2.y, + player1score, + player2score, + player1nukescore, + player2nukescore, + ball[1].x, + ball[1].y, + gameState, + ball[1].dx, + ballSpeed, + paddle_SPEED, + player2striken, + areanuclear = p[1], die, tonumber(p[4]), tonumber(p[5]), tonumber(p[6]), tonumber(p[7]), tonumber(p[8]), tonumber(p[9]), tonumber(p[10]), p[11], tonumber(p[12]), tonumber(p[13]), tonumber(p[14]), tonumber(p[15]), tonumber(p[16]) + --print("ACCEPTED") + else + --print("DECLINED") + end + else + if tonumber(p[9]) > VIRTUAL_WIDTH/2 then + die = tonumber(p[2]) + lastSentKeyClient, + ball[1].dy, + player2.y, + player1score, + player2score, + player1nukescore, + player2nukescore, + ball[1].x, + ball[1].y, + gameState, + ball[1].dx, + ballSpeed, + paddle_SPEED, player2striken, + areanuclear = p[1], die, tonumber(p[4]), tonumber(p[5]), tonumber(p[6]), tonumber(p[7]), tonumber(p[8]), tonumber(p[9]), tonumber(p[10]), p[11], tonumber(p[12]), tonumber(p[13]), tonumber(p[14]), tonumber(p[15]), tonumber(p[16]) + --print("ACCEPTED") + else + --print("ENFORCED" .. ball[1].x .. " " .. ball[1].dx) + lastSentKeyClient = p[1] + player2striken = tonumber(p[15]) + player2.y = tonumber(p[4]) + end + end + end + end + end +until not data + if not datawaspassed then + datawaspassedtimer = datawaspassedtimer + 1 + if datawaspassedtimer > 15 then + confirmation = "D" + datawaspassedtimer = 0 + end + else + datawaspassedtimer = 0 + end +end +function clienttest(dt) + if clientinit == false then + local socket = require "socket" + local address, port = IP, 12345 + + udp = socket.udp() + udp:setpeername(address, port) + udp:settimeout(0) + clientinit = true + end + if isAndroid then + if table.empty(touches) then + lastSentKey = "g" + end + end + ts = ts + dt + if ts > updaterate then + udp:send(tostring(lastSentKey) .. + '|' .. tostring(ball[1].dy) .. + '|' .. tostring(player1.y) .. + '|' .. tostring(player2.y) .. + '|' .. tostring(player1score) .. + '|' .. tostring(player2score) .. + '|' .. tostring(player1nukescore) .. + '|' .. tostring(player2nukescore) .. + '|' .. tostring(ball[1].x) .. + '|' .. tostring(ball[1].y) .. + '|' .. gameState .. + '|' .. tostring(ball[1].dx) .. + '|' .. tostring(ballSpeed) .. + '|' .. tostring(paddle_SPEED) .. + '|' .. tostring(player2striken) .. + '|' .. tostring(areanuclear) .. + "|CLIENT") + ts = 0 + end + local data + local datanumtest = 0 + local datawaspassed = false + repeat + datanumtest = datanumtest + 1 + --print("LATENCY: " .. tostring(datanumtest)) + data = udp:receive() + + if data then + --print("RECEIVED DATA: " .. data) + datawaspassed = true + --print("SENT TO SERVER:" .. lastSentKey) + confirmation = "N" + local p = split(data, '|') + if p[17] then + if p[17] ~= "HOST" then + confirmation = "U" + end + if tonumber(p[18]) > 90 then + confirmation = "L" + end + for i = 1, maxBalls do + local die = tonumber(p[2]) + if (ball[i].x <= VIRTUAL_WIDTH/2) then + if tonumber(p[9]) <= VIRTUAL_WIDTH/2 then + lastSentKeyClient, ball[i].dy, player1.y, player1score, player2score, player1nukescore, player2nukescore, ball[i].x, ball[i].y, gameState, ball[i].dx, ballSpeed, paddle_SPEED, player1striken, areanuclear = p[1], die, tonumber(p[4]), tonumber(p[5]), tonumber(p[6]), tonumber(p[7]), tonumber(p[8]), tonumber(p[9]), tonumber(p[10]), p[11], tonumber(p[12]), tonumber(p[13]), tonumber(p[14]), tonumber(p[15]), tonumber(p[16]) + --print("ACCEPTED") + else + --print("DECLINED") + end + else + if tonumber(p[9]) <= VIRTUAL_WIDTH/2 then + lastSentKeyClient, ball[i].dy, player1.y, player1score, player2score, player1nukescore, player2nukescore, ball[i].x, ball[i].y, gameState, ball[i].dx, ballSpeed, paddle_SPEED, player1striken, areanuclear = p[1], die, tonumber(p[4]), tonumber(p[5]), tonumber(p[6]), tonumber(p[7]), tonumber(p[8]), tonumber(p[9]), tonumber(p[10]), p[11], tonumber(p[12]), tonumber(p[13]), tonumber(p[14]), tonumber(p[15]), tonumber(p[16]) + --print("REROUTED") + else lastSentKeyClient = p[1] + player1.y = tonumber(p[4]) + player1striken = tonumber(p[15]) + --print("ENFORCED") + end + end + end + else + confirmation = "U" + end + end + --print("GOT: " .. lastSentKeyClient) + until not data + if not datawaspassed then + datawaspassedtimer = datawaspassedtimer + 1 + if datawaspassedtimer > 15 then + confirmation = "D" + datawaspassedtimer = 0 + end + else + datawaspassedtimer = 0 + end +end +function wallbreaker(x, y) + if (gameState == "editor") then + for i, wall in ipairs(walls) do + if math.abs(wall.wallx - x) < 10 and math.abs(wall.wally - y) < 10 then + table.remove(walls, i) + end + end + end +end + +function hardmanager(diff) + selecting = 1 + if (diff == "easy") then + INDIC[1] = ">" + AGAINST_AI = 1 + AI_SPEED = ballSet + AI_STRIKEMOD = 100 + AI_NUKEMOD = 1000 + AI_LEVEL = 350 + difficultyl = 200 + selecting = 0 + gameState = "1serve" + globalState = "base" + end + if (diff == "normal") then + INDIC[2] = ">" + AI_SPEED = ballSet + AI_LEVEL = 500 + AI_NUKEMOD = 250 + AI_STRIKEMOD = 60 + AGAINST_AI = 1 + difficultyl = 300 + selecting = 0 + gameState = "1serve" + globalState = "base" + end + if (diff == "hard") then + INDIC[3] = ">" + AI_SPEED = ballSpeed * 1.1 + 50 + AI_LEVEL = 700 + AI_NUKEMOD = 200 + AI_STRIKEMOD = 20 + selecting = 0 + difficultyl = 350 + AGAINST_AI = 1 + gameState = "1serve" + globalState = "base" + end + if (diff == "smart") then + INDIC[3] = ">" + AI_SPEED = ballSpeed * 1.1 + 50 + AI_LEVEL = 1500 + AI_NUKEMOD = 200 + AI_STRIKEMOD = 20 + selecting = 0 + difficultyl = 350 + AGAINST_AI = 1 + gameState = "1serve" + globalState = "base" + end + if (diff == "practice") then + INDIC[3] = ">" + AI_SPEED = ballSpeed * 500 + 50 + AI_LEVEL = 700 + AI_NUKEMOD = 9000000000 + AI_STRIKEMOD = 90000000 + selecting = 0 + difficultyl = 350 + AGAINST_AI = 1 + gameState = "base" + end +end + +function dangerChecker() --CHECK IF CONTROLS ARE DUPLICATING + if (p1control.up == p1control.down) then + danger = "1up" + danger2 = "1down" + elseif (p1control.up == p1control.super) then + danger = "1up" + danger2 = "1special" + elseif (p1control.up == p1control.counter) then + danger = "1up" + danger2 = "1ct" + elseif (p1control.down == p1control.super) then + danger = "1down" + danger2 = "1special" + elseif (p1control.down == p1control.counter) then + danger = "1ct" + danger2 = "1down" + elseif (p1control.super == p1control.counter) then + danger = "1special" + danger2 = "1ct" + elseif (p2control.down == p2control.up) then + danger = "2down" + danger2 = "2up" + elseif (p2control.down == p2control.super) then + danger = "2down" + danger2 = "2special" + elseif (p2control.down == p2control.counter) then + danger = "2down" + danger2 = "2ct" + elseif (p2control.up == p2control.super) then + danger = "2up" + danger2 = "2special" + elseif (p2control.up == p2control.counter) then + danger = "2ct" + danger2 = "2up" + elseif (p2control.super == p2control.counter) then + danger = "2special" + danger2 = "2ct" + else + danger = "none" + danger2 = "none" + end +end +function love.keypressed(key) + if not isAndroid then + lastSentKey = key + end + + if gameState == "chooseIP" then + if key == "backspace" then + -- get the byte offset to the last UTF-8 character in the string. + local byteoffset = utf8.offset(IPnew, -1) + + if byteoffset then + -- remove the last UTF-8 character. + -- string.sub operates on bytes rather than UTF-8 characters, so we couldn't do string.sub(text, 1, -2). + IPnew = string.sub(IPnew, 1, byteoffset - 1) + end + end + end + if gameState == "assign" then + if (req == "p1up") then + p1control.up = key + currentKey = key + --love.window.setTitle(key) + gameState = "controlSettings" + end + if (req == "p2up") then + p2control.up = key + currentKey = key + --love.window.setTitle(key) + gameState = "controlSettings" + end + if (req == "p1down") then + p1control.down = key + currentKey = key + --love.window.setTitle(key) + gameState = "controlSettings" + end + if (req == "p2down") then + p2control.down = key + currentKey = key + -- love.window.setTitle(key) + gameState = "controlSettings" + end + if (req == "p1super") then + p1control.super = key + currentKey = key + -- love.window.setTitle(key) + gameState = "controlSettings" + end + if (req == "p2super") then + p2control.super = key + currentKey = key + -- love.window.setTitle(key) + gameState = "controlSettings" + end + if (req == "p1ct") then + p1control.counter = key + currentKey = key + -- love.window.setTitle(key) + gameState = "controlSettings" + end + if (req == "p2ct") then + p2control.counter = key + currentKey = key + --love.window.setTitle(key) + gameState = "controlSettings" + end + end + if key == "escape" then + if not isAndroid and globalState == "base" and gameState ~= "done" then + if paused then + paused = false + TEXT = "Let's Continue" + else + paused = true + TEXT = "PAUSED" + end + + end + elseif key == "enter" or key == "return" then + if gameState == "start" then + resettinggenius() + gameState = "menu" + ball[1].dx = 1 + ball[1].dy = 1 + globalState = "menu" + hardmanager() + elseif (gameState == "done") then + if (player1score > player2score) then + gameState = "2serve" + potentialnuke1 = 0 + potentialnuke2 = 0 + striken = 0 + if (nuckemodactive == 0) then + areanuclear = 0 + nuclearanimation = 3 + end + potentialstrike1 = 0 + potentialstrike2 = 0 + player1nukescore = 0 + player2nukescore = 0 + else + gameState = "1serve" + resettinggenius() + for i = 1, maxBalls do + ball[i]:reset(i, 1) + end + end + else + gameState = "menu" + ball[1].dx = 1 + ball[1].dy = 1 + globalState = "menu" + if (love.math.random(0, 20) == 1) then + TEXT = "Nuclear Ching Chong" + else + TEXT = "Nuclear Pong" + end + resettinggenius() + for i = 1, maxBalls do + ball[i]:reset(i) + end + end + end +end + +function love.keyreleased(key) + currentKey = " " + if lastSentKey == key and not isAndroid then + lastSentKey = "g" + end +end +function speedSetter(requesttype) + if (requesttype == "ball") then + if (ballSet > 550) then + ballSet = 0 + paddle_SPEED = 0 + else + ballSet = ballSet + 50 + paddle_SPEED = paddle_SPEED + 5 + end + ballSpeed = ballSet + background_scroll_speed = ballSpeed / 20 + end + if (requesttype == "snc") then + synctype = synctype + 1 + if (synctype > 1) then + synctype = 0 + end + + if synctype == 0 then + synctext = "Independent" + end + if synctype == 1 then + synctext = "Synchronised" + end + end + if (requesttype == "nuclearmod") then + nuckemodactive = nuckemodactive + 1 + if (nuckemodactive > 1) then + nuckemodactive = 0 + end + if (nuckemodactive == 0) then + areanuclear = 0 + nuclearanimation = 3 + ballSet = 200 + TEXT = "Nuclear Pong" + + synctype = 0 + maxspeed = 700 + synctext = "Independent" + paddle_SPEED = ballSet + AI_SPEED = ballSet + end + if (nuckemodactive == 1) then + areanuclear = 1 + ballSet = 2000 + maxspeed = 2000 + paddle_SPEED = ballSet + AI_SPEED = ballSet + synctext = "death is imminent" + end + ballSpeed = ballSet + background_scroll_speed = ballSpeed / 20 + end + if (requesttype == "practice") then + if (ballSpeed > 999) then + ballSpeed = 200 + background_scroll_speed = ballSpeed / 20 + ballSet = 200 + end + if (ballSpeed > 799) then + prtext = "Insane" + maxBalls = 5 + elseif ballSpeed > 599 then + prtext = "Hard" + maxBalls = 4 + elseif ballSpeed > 399 then + prtext = "Normal" + maxBalls = 3 + elseif ballSpeed > 199 then + prtext = "Easy" + maxBalls = 3 + end + ballSpeed = ballSpeed + 200 + background_scroll_speed = ballSpeed / 20 + ballSet = ballSet + 200 + end + if (requesttype == "reset") then + ballSpeed = 200 + background_scroll_speed = ballSpeed / 20 + ballSet = 200 + synctype = 0 + prtext = "Easy" + maxBalls = 1 + end + if (requesttype == "pc") then + if (playerCount == 2) then + playerCount = 1 + playertext = "1v1" + elseif (playerCount == 1) then + playerCount = playerCount + 1 + player3.x = player1.x + VIRTUAL_WIDTH / 2 + player3.y = player3.y + playertext = "2v2" + end + end + if (requesttype == "ballz") then + if (maxBalls > 1) then + --love.window.setTitle("more than 4") + maxBalls = 1 + else + maxBalls = maxBalls + 1 + end + end + if requesttype == "ptw" then + if ptw == 10 then + ptw = 1 + else + ptw = ptw + 1 + end + end +end + +function gameModeChanger() + if (gameState == "gameMode") then + local button_width = VIRTUAL_WIDTH * (1 / 3) + local BUTTON_HEIGHT = 50 + local margin = 20 + local hot = false + local cursor_y = 0 + local total_height = (BUTTON_HEIGHT + margin) * #buttons + for i, button in ipairs(modeSelectorButtons) do + button.last = button.now + local bx = (VIRTUAL_WIDTH * 0.5) - (button_width * 0.5) + local by = (VIRTUAL_HEIGHT * 0.5) - (total_height * 0.5) + cursor_y + local color = {255, 255, 255, 255} + local mx, my = love.mouse.getPosition() + mx = mx + my = my + mx = mx * DIFFERENCE_X + my = my * DIFFERENCE_Y + hot = (mx > bx and mx < bx + button_width and my > by and my < by + BUTTON_HEIGHT) and i + if (hot == i) then + color = {10, 10, 0, 255} + end + button.now = love.mouse.isDown(1) + if button.now and not button.last and hot == i then + love.graphics.setColor(0, 0, 0, 1) + love.graphics.rectangle("fill", 0, 0, VIRTUAL_WIDTH, VIRTUAL_HEIGHT) + sounds["wallhit"]:play() + button.fn() + end + love.graphics.setColor(unpack(color)) + love.graphics.rectangle("fill", bx, by, button_width, BUTTON_HEIGHT) + love.graphics.setColor(0, 0, 0, 255) + local textW = smallfont:getWidth(button.text) + local textH = smallfont:getHeight(button.text) + love.graphics.print(button.text, smallfont, VIRTUAL_WIDTH * 0.5 - textW * 0.5, by + textH * 0.5) + love.graphics.setColor(255, 255, 255, 255) + cursor_y = cursor_y + (BUTTON_HEIGHT + margin) + end + end + if (gameState == "multiMode") then + local button_width = VIRTUAL_WIDTH * (1 / 3) + local BUTTON_HEIGHT = 50 + local margin = 20 + local hot = false + local cursor_y = 0 + local total_height = (BUTTON_HEIGHT + margin) * #buttons + for i, button in ipairs(playerCountButtons) do + button.last = button.now + + local bx = (VIRTUAL_WIDTH * 0.5) - (button_width * 0.5) + + local by = (VIRTUAL_HEIGHT * 0.3) - (total_height * 0.5) + cursor_y + if (button.text == "Play") then + by = by + by / 1.8 + end + local color = {255, 255, 255, 255} + local mx, my = love.mouse.getPosition() + mx = mx + my = my + mx = mx * DIFFERENCE_X + my = my * DIFFERENCE_Y + hot = (mx > bx and mx < bx + button_width and my > by and my < by + BUTTON_HEIGHT) and i + if (hot == i) then + if (button.text == "Play") then + color = {0 / 255, 255 / 255, 0 / 255, 255} + else + color = {10, 10, 0, 255} + end + end + button.now = love.mouse.isDown(1) + if button.now and not button.last and hot == i then + love.graphics.setColor(0, 0, 0, 1) + love.graphics.rectangle("fill", 0, 0, VIRTUAL_WIDTH, VIRTUAL_HEIGHT) + sounds["wallhit"]:play() + if button.text == "Ball Speed: " and nuckemodactive == 1 then + else + button.fn() + end + end + love.graphics.setColor(unpack(color)) + love.graphics.rectangle("fill", bx, by, button_width, BUTTON_HEIGHT) + love.graphics.setColor(0, 0, 0, 255) + local textW = smallfont:getWidth(button.text) + local textH = smallfont:getHeight(button.text) + if (button.text == "1v1") then + love.graphics.print(playertext, smallfont, VIRTUAL_WIDTH * 0.5 - textW * 0.5, by + textH * 0.5) + elseif button.text == "snc" then + if (nuckemodactive == 1) then + love.graphics.setColor(1, 0, 0, 1) + love.graphics.print(synctext, smallfont, VIRTUAL_WIDTH * 0.5 - textW * 0.5, by + textH * 0.5) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.print(synctext, smallfont, VIRTUAL_WIDTH * 0.5 - textW * 0.5, by + textH * 0.5) + love.graphics.setColor(0, 0, 0, 1) + else + -- + love.graphics.print(synctext, smallfont, VIRTUAL_WIDTH * 0.45 - textW * 0.5, by + textH * 0.5) + end + elseif (button.text == "ballCount") then + love.graphics.print( + "Ball Count: " .. maxBalls, + smallfont, + VIRTUAL_WIDTH * 0.5 - textW * 0.5, + by + textH * 0.5 + ) + elseif (button.text == "Ball Speed: ") then + if (nuckemodactive == 1) then + love.graphics.setColor(1, 0, 0, 1) + love.graphics.print( + "shaitan machina", + smallfont, + VIRTUAL_WIDTH * 0.5 - textW * 0.5, + by + textH * 0.5 + ) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.print( + "shaitan machina", + smallfont, + VIRTUAL_WIDTH * 0.5 - textW * 0.5, + by + textH * 0.5 + ) + love.graphics.setColor(0, 0, 0, 1) + else + love.graphics.print( + button.text .. ballSet, + smallfont, + VIRTUAL_WIDTH * 0.5 - textW * 0.5, + by + textH * 0.5 + ) + end + elseif button.text == "ptw" then + love.graphics.print( + "Points to Win: " .. ptw, + smallfont, + VIRTUAL_WIDTH * 0.5 - textW * 1.5, + by + textH * 0.5 + ) + else + love.graphics.print(button.text, smallfont, VIRTUAL_WIDTH * 0.5 - textW * 0.5, by + textH * 0.5) + end + love.graphics.setColor(255, 255, 255, 255) + cursor_y = cursor_y + (BUTTON_HEIGHT + margin) + end + end +end + +function love.draw(dt) + simpleScale.set() + + if globalState == "selfhost" then + globalState = "nettest" + baseDraw() + globalState = "selfhost" + else + baseDraw() + end + if (globalState == "nettest" or globalState == "clienttest" or globalState == "selfhost") and confirmation == "D" then + love.graphics.clear(50 / 255, 50 / 255, 50 / 255, 255) + love.graphics.printf("WAIT FOR OPPONENT", 0, VIRTUAL_HEIGHT / 2, VIRTUAL_WIDTH, "center") + end + if (globalState == "nettest" or globalState == "clienttest" or globalState == "selfhost") and confirmation == "U" then + love.graphics.clear(50 / 255, 50 / 255, 50 / 255, 255) + love.graphics.printf("LOBBY FULL OR WRONG MODE CHOSEN", 0, VIRTUAL_HEIGHT / 2, VIRTUAL_WIDTH, "center") + end + if (globalState == "nettest" or globalState == "clienttest" or globalState == "selfhost") and confirmation == "L" then + love.graphics.clear(50 / 255, 50 / 255, 50 / 255, 255) + love.graphics.printf("POOR CONNECTION TO SERVER", 0, VIRTUAL_HEIGHT / 2, VIRTUAL_WIDTH, "center") + end + if (globalState == "nettest" or globalState == "clienttest" or globalState == "selfhost") and confirmation == "S" then + love.graphics.clear(50 / 255, 50 / 255, 50 / 255, 255) + love.graphics.printf("INTERNAL SERVER WAITING", 0, VIRTUAL_HEIGHT / 2, VIRTUAL_WIDTH, "center") + love.graphics.printf(myip, 0, VIRTUAL_HEIGHT / 2 + 120, VIRTUAL_WIDTH, "center") + end + if isAndroid then + androidDraw() + love.keyboard.mouseisReleased = false + end + if debug then + if touches then + for i, touch in ipairs(touches) do + love.graphics.printf(touch.x, 0, VIRTUAL_HEIGHT / 2, VIRTUAL_WIDTH, "center") + end + if doubleclick1 then + TEXT = "DOUBLECLICK1" + elseif doubleclick2 then TEXT = "DOUBLECLICK2" + else TEXT = "NO" + end + end + end + if wallsLoadError then + love.graphics.setColor(1,0,0,1) + love.graphics.printf("Error loading map!", 0,0,VIRTUAL_WIDTH, "left") + end + simpleScale.unSet() +end + +--Check if controls are duplicating +function controllerSer() + for i = 1, maxBalls do + if (ball[i].dy == 0) then + hitNum[i] = hitNum[i] + 1 + if hitNum[i] >= 10 then + ball[i].dy = 1 + hitNum[i] = 0 + end + else + hitNum[i] = 0 + end + end +end + +function palleteController() --!!!!LEGACY CODE, MIGRATED TO Paddle.lua!!!! + if (areanuclear == 0) then + player1.RED = 1 + player1.GREEN = 1 + player1.BLUE = 1 + end + if (areanuclear == 0) then + player2.RED = 1 + player2.GREEN = 1 + player2.BLUE = 1 + end + if (areanuclear == 1) then + player1.RED = 0 + player1.GREEN = 0 + player1.BLUE = 0 + end + if (areanuclear == 1) then + player2.RED = 0 + player2.GREEN = 0 + player2.BLUE = 0 + end +end + +function love.wheelmoved(x, y) + if (y < 0 and wall1width > 0) then + wall1width = wall1width - 5 + elseif y > 0 and wall1width < 900 then + wall1width = wall1width + 5 + end +end + +function serveBot() --THIS IS USED TO CHANGE TEXT/BALL DIRECTION ON DIFFERENT SERVES + --print("servebot called") + if (gameState == "1serve") then + updateTEXT = "" + if (gameMode ~= "practice") then + if isAndroid then + TEXT = "PLAYER 1, serve!(double-click)" + else + TEXT = "PLAYER 1, serve!(q)" + end + end + if ((globalState ~= "clienttest" and love.keyboard.isDown("q")) or (globalState == "clienttest" and lastSentKeyP1 == "q") or doubleclick1) then + TEXT = "Lets Begin!" + doubleclick1 = false + ball_DIR = 1 + if maxBalls == 1 then + ball[1]:reset(1, 1) + else + for i = 1, maxBalls do + ball[i]:reset(i) + end + end + gameState = "play" + + end + end + if (gameState == "2serve") then + if (gameMode ~= "practice") then + if isAndroid then + TEXT = "PLAYER 2, serve!(double-click)" + else + TEXT = "PLAYER 2, serve!(p)" + end + end + if (AGAINST_AI == 1) then + TEXT = "" + doubleclick2 = false + ball_DIR = -1 + if maxBalls == 1 then + ball[2]:reset(i, 2) + else + for i = 1, maxBalls do + ball[i]:reset(i) + end + end + + gameState = "play" + + end + if (((globalState == "nettest" and lastSentKeyClient == "p") or ((globalState ~= "nettest") and love.keyboard.isDown("p")) or doubleclick2)and AGAINST_AI == 0) then + TEXT = "Lets Begin" + doubleclick2 = false + ball_DIR = -1 + if maxBalls == 1 then + ball[1]:reset(1, 2) + else + for i = 1, maxBalls do + ball[i]:reset(i) + end + end + --love.window.setTitle("An atttttttt") + gameState = "play" + + end + end +end +function mapChanger() + if (gameState == "editor") then + MAP_TYPE = 2 + end + if (MAP_TYPE > 2) then + MAP_TYPE = 0 + end + +end +function resolutionChanger() + if (RESOLUTION_SET > 1) then + RESOLUTION_SET = 0 + end + if (RESOLUTION_SET == 0) then + if (isFullscreen == 1) then + DIFFERENCE_X = 1 + DIFFERENCE_Y = 1 + OFFSET_X = 0 + OFFSET_Y = 0 + simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = false}) + isFullscreen = 0 + end + end + if (RESOLUTION_SET == 1) then + if (isFullscreen == 0) then + simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = true}) + local newWidth = love.graphics.getWidth() + local newHeight = love.graphics.getHeight() + DIFFERENCE_X = VIRTUAL_WIDTH / newWidth + DIFFERENCE_Y = VIRTUAL_HEIGHT / newHeight + OFFSET_X = math.fmod(newWidth, VIRTUAL_WIDTH) / 2 + OFFSET_Y = math.fmod(newHeight, VIRTUAL_HEIGHT) / 2 + isFullscreen = 1 + end + end +end +function resettinggenius() + maxBalls = 1 + for i = 1, maxBalls do + ball[i]:reset(i) + end + paddle_SPEED = 200 + nuclearanimation = 3 + timeIsSlow = false + timeIsSlow2 = false + serverinit = false + ts = 0 + originalSpeed = 200 + gameState = "menu" + ball[1].dx = 1 + ball_DIR = 1 + ball[1].dy = 1 + globalState = "menu" + gameMode = "normal" + player1.height = 100 + player2.height = 100 + ballSet = 200 + ballSpeed = ballSet + background_scroll_speed = ballSpeed / 20 + player2.GREEN = 255 + player2.BLUE = 255 + player1.GREEN = 255 + player1.BLUE = 255 + player1score = 0 + player2score = 0 + potentialnuke1 = 0 + potentialnuke2 = 0 + striken = 0 + areanuclear = 0 + potentialstrike1 = 0 + potentialstrike2 = 0 + player1nukescore = 0 + player2nukescore = 0 + player1reverbav = 0 + player2reverbav = 0 + selecting = 0 + AGAINST_AI = 0 +end + +function love.mousereleased(x, y, button) + love.keyboard.mouseisReleased = true + if (gameState == "editor") then + if (#walls < 1000 and button == 1 and blockinput ~= true) then + table.insert(walls, newWall((x ) * DIFFERENCE_Y , (y ) * DIFFERENCE_Y , 10, wall1width)) + end + end +end + +function ballsAlive() + for i = 1, maxBalls do + if ball[i].disabled == false then + --print("Ball " .. i .. " is not disabled") + return true + end + end + return false +end +function split(s, delimiter) + result = {} + for match in (s..delimiter):gmatch("(.-)"..delimiter) do + table.insert(result, match) + end + return result +end +address, port = IP, 12345 +function checkCurrentServer(dt) + if GetIPType(IP) ~= 1 then + status = "offline" + end + if GetIPType(IP) == 1 then + if dserverinit == false then + --print("Switching IP") + socket = require "socket" + address, port = IP, 12345 + --print(address) + udp = socket.udp() + udp:setpeername(address, port) + udp:settimeout(0) + dserverinit = true + end + if IP ~= address then dserverinit = false--print(IP .. " doesnt equal " .. address) + else + ts = ts + dt + --print(ts) + if ts > checkrate then + status = "offline" + --print("sent ping") + udp:send("HELLO") + local data + data = udp:receive() + if data then + --print("got answer!") + local p = split(data, '|') + status = p[1] + print("answer is " .. status) + else + print("no response!") + end + ts = 0 + end +end +end + +end +local gts = 0 +hostinit = false +player1ip = "127.0.0.1" +player1port = "12345" +player2ip = "none" +player2port = nil +local p1ping = 0 +local p2ping = 0 +local requesterip +local requresterport +function selfHost(dt) + --print("Server running") + if not hostinit then + local socket = require('socket') + udp = socket.udp() + udp:setsockname('*', 12345) + udp:settimeout(0) + local s = socket.udp() + s:setpeername("74.125.115.104",80) + myip, _ = s:getsockname() + + hostinit = true + else + gts = gts + dt + if gts > 0.015 then + local data, msg_or_ip, port_or_nil + local p1data, p2data + if table.empty(touches) then + lastSentKey = "g" +end + repeat + + data, msg_or_ip, port_or_nil = udp:receivefrom() + if data then + + if data == "HELLO" then + --print("getting pinged") + requesterip = msg_or_ip + requesterport = port_or_nil + else + --print(string.sub(data,1,1) .. "Playerlist: " .. player1ip .. " " .. player2ip) + if player2ip == msg_or_ip then + p2data = data .. '|' .. p2ping + p2ping = 0 + else + if player2ip == "none" and msg_or_ip ~= player1ip then + player2ip = msg_or_ip + p2data = data .. '|' .. p2ping + p2ping = 0 + player2port = port_or_nil + --print("CONNECTED: PLAYER 2 FROM: " .. player2ip) + elseif (player1ip ~= msg_or_ip and player2ip ~= msg_or_ip) then + --print("Lobby Full!" .. player1ip .. player2ip) + end + end + + end + end + until not data + if player1ip ~= "none" then + p1ping = p1ping + 1 + end + if player2ip == "none" then + confirmation = "S" + else + --print("Player2: " .. player2ip) + p2ping = p2ping + 1 + if p2ping > 100 then + for i = 1, maxBalls do + ts = ts + dt + if ts > updaterate then + udp:sendto(tostring(lastSentKey) .. + '|' .. tostring(ball[1].dy) .. + '|' .. tostring(player2.y) .. + '|' .. tostring(player1.y) .. + '|' .. tostring(player1score) .. + '|' .. tostring(player2score) .. + '|' .. tostring(player1nukescore) .. + '|' .. tostring(player2nukescore) .. + '|' .. tostring(ball[1].x) .. + '|' .. tostring(ball[1].y) .. + '|' .. gameState .. + '|' .. tostring(ball[1].dx) .. + '|' .. tostring(ballSpeed) .. + '|' .. tostring(paddle_SPEED) .. + '|' .. tostring(player1striken) .. + '|' .. tostring(areanuclear) .. + "|HOST|".. p2ping, player2ip, player2port) + ts = 0 + end + end + --print("PLAYER 2 DISCONNECTED") + p2data = nil + player2ip = "none" + player2port = nil + end + end + if player2port then + for i = 1, maxBalls do + ts = ts + dt + if ts > updaterate then + udp:sendto(tostring(lastSentKey) .. + '|' .. tostring(ball[1].dy) .. + '|' .. tostring(player2.y) .. + '|' .. tostring(player1.y) .. + '|' .. tostring(player1score) .. + '|' .. tostring(player2score) .. + '|' .. tostring(player1nukescore) .. + '|' .. tostring(player2nukescore) .. + '|' .. tostring(ball[1].x) .. + '|' .. tostring(ball[1].y) .. + '|' .. gameState .. + '|' .. tostring(ball[1].dx) .. + '|' .. tostring(ballSpeed) .. + '|' .. tostring(paddle_SPEED) .. + '|' .. tostring(player1striken) .. + '|' .. tostring(areanuclear) .. + "|HOST|".. p2ping, player2ip, player2port) + ts = 0 + end + end + --print("SENT TO " .. player2ip .. ":" .. player2port .. " : " ..lastSentKey) + end + local datanumtest = 0 + local datawaspassed = false + if p2data and player1port then + datawaspassed = true + --print("ReceivedINFO: " .. p2data) + confirmation = "N" + local p = split(p2data, '|') + if p[17] then + if tonumber(p[18]) > 90 then + confirmation = "L" + end + if p[17] ~= "CLIENT" then + confirmation = "U" + end + elseif p[1] == "RESPONSE" then + if p[2] == "1" then + + elseif p[2] == "2" then + + elseif p[2] == "3" then + end + else + confirmation = "U" + end + + if p[17] then + if ball[1].disabled and ball[1].x > 20 and ball[1].x < VIRTUAL_WIDTH - 20 then + ball[1].disabled = false + --print("illegal disabling") + end + if gameState ~= "1serve" then + if (ball[1].x > VIRTUAL_WIDTH/2) then + if tonumber(p[9]) > VIRTUAL_WIDTH/2 then + die = tonumber(p[2]) + lastSentKeyClient, + ball[1].dy, + player2.y, + player1score, + player2score, + player1nukescore, + player2nukescore, + ball[1].x, + ball[1].y, + gameState, + ball[1].dx, + ballSpeed, + paddle_SPEED, player2striken, + areanuclear = p[1], die, tonumber(p[4]), tonumber(p[5]), tonumber(p[6]), tonumber(p[7]), tonumber(p[8]), tonumber(p[9]), tonumber(p[10]), p[11], tonumber(p[12]), tonumber(p[13]), tonumber(p[14]), tonumber(p[15]), tonumber(p[16]) + --print("ACCEPTED") + else + --print("DECLINED") + end + else + if tonumber(p[9]) > VIRTUAL_WIDTH/2 then + die = tonumber(p[2]) + lastSentKeyClient, + ball[1].dy, + player2.y, + player1score, + player2score, + player1nukescore, + player2nukescore, + ball[1].x, + ball[1].y, + gameState, + ball[1].dx, + ballSpeed, + paddle_SPEED, player2striken, + areanuclear = p[1], die, tonumber(p[4]), tonumber(p[5]), tonumber(p[6]), tonumber(p[7]), tonumber(p[8]), tonumber(p[9]), tonumber(p[10]), p[11], tonumber(p[12]), tonumber(p[13]), tonumber(p[14]), tonumber(p[15]), tonumber(p[16]) + --print("ACCEPTED") + else + --print("ENFORCED" .. ball[1].x .. " " .. ball[1].dx) + lastSentKeyClient = p[1] + player2.y = tonumber(p[4]) + player2striken = tonumber(p[15]) + end + end + end + end + --print("SENT TO " .. player1ip .. ":" .. player1port .. " : " .. string.sub(p2data,1,1)) + --print("1::" .. p1data) + --print("2::" .. p2data) + --print("SENT1: " .. player2ip .. " " .. player2port .. " " .. p1data) + --print("SENT2: " .. player1ip .. " " .. player1port .. " " .. p2data) + end + if requesterip then + --print("getting pnged!") + if player2ip == "none" then + udp:sendto("clienttest", requesterip, requesterport) + --print("clienttest av to: " .. requesterip) + else + udp:sendto("full", requesterip, requesterport) + --print("full to: " .. msg_or_ip) + end + requesterip, requesterport = nil + end + gts = 0 + end +end +end +local lastclick = 0 +local clickInterval = 0.4 +function love.touchpressed( id, x, y, dx, dy, pressure ) + if isAndroid then + if x < love.graphics.getWidth()-OFFSET_X/2 then + actualX = (x - OFFSET_X/2) * DIFFERENCE_Y + else + actualX = 1380 + end + local existsingID = touchExists(id) + if existsingID ~= -1 then + touches[existsingID].x = actualX + touches[existsingID].y = (y) * DIFFERENCE_Y + else + table.insert(touches, newTouch(id, actualX , (y) * DIFFERENCE_Y)) + local time = love.timer.getTime() + if actualX < VIRTUAL_WIDTH/2 then + if time <= lastclick + clickInterval and actualX> 100 then + doubleclick1 = true + if gameState == "1serve" then + lastSentKey = "q" + else + lastSentKey = p1control.super + end + else + doubleclick1 = false + lastclick = time + end + + else + if time <= lastclick + clickInterval and actualX < VIRTUAL_WIDTH-100 then + doubleclick2 = true + if gameState == "2serve" then + lastSentKey = "p" + else + lastSentKey = p2control.super + end + else + doubleclick2 = false + lastclick = time + end + end + end + end +end +function love.touchreleased( id, x, y, dx, dy, pressure ) + if isAndroid then + if gameState == "start" then + resettinggenius() + gameState = "menu" + ball[1].dx = 1 + ball_DIR = 1 + ball[1].dy = 1 + globalState = "menu" + hardmanager() + + end + local existsingID = touchExists(id) + if existsingID ~= -1 then + table.remove(touches, existsingID) + end + end +end +function love.touchmoved( id, x, y, dx, dy, pressure ) + if isAndroid then + if x < love.graphics.getWidth()-OFFSET_X/2 then + actualX = (x - OFFSET_X/2) * DIFFERENCE_Y + else + actualX = 1380 + end + local existsingID = touchExists(id) + if existsingID ~= -1 then + touches[existsingID].x = actualX + touches[existsingID].y = (y ) * DIFFERENCE_Y + if touches[existsingID].originalX - touches[existsingID].x > 200 and + touches[existsingID].originalX < VIRTUAL_WIDTH/2 then + hold1 = true + lastSentKey = p1control.counter + else + hold1 = false + end + if touches[existsingID].x - touches[existsingID].originalX > 200 and + touches[existsingID].originalX > VIRTUAL_WIDTH/2 then + hold2 = true + + lastSentKey = p2control.counter + else + hold2 = false + end + end + end +end +function touchExists(ID) + for i, touch in ipairs(touches) do + if touch.id == ID then + return i + end + end + return -1 +end +function table.empty (self) + for _, _ in pairs(self) do + return false + end + return true +end +function sectortouched(sector) +for i, touch in ipairs(touches) do + if (AGAINST_AI == 1) then + if sector == 2 and touch.x < 100 and touch.y < player1.y then + lastSentKey = p1control.up + return true + elseif sector == 2 and touch.x > VIRTUAL_WIDTH/2+10 and touch.y < player1.y then + lastSentKey = p1control.up + return true + elseif sector == 3 and touch.x < 100 and touch.y > player1.y+player1.height*0.9 then + lastSentKey = p1control.down + return true + elseif sector == 3 and touch.x > VIRTUAL_WIDTH/2+10 and touch.y > player1.y+player1.height*0.9 then + lastSentKey = p1control.down + return true + end + else + if sector == 1 and touch.x > VIRTUAL_WIDTH-100 and touch.y < player2.y then + lastSentKey = p2control.up + return true + elseif sector == 2 and touch.x < 100 and touch.y < player1.y then + lastSentKey = p1control.up + return true + elseif sector == 3 and touch.x < 100 and touch.y > player1.y+player1.height*0.9 then + lastSentKey = p1control.down + return true + elseif sector == 4 and touch.x > VIRTUAL_WIDTH-100 and touch.y > player2.y+player1.height*0.9 then + lastSentKey = p2control.down + return true + end +end +end +return false +end + +function resetButtonX(arr) + for i, buttons in ipairs(arr) do + buttons.x = 1300 + end +end + diff --git a/font.ttf b/font.ttf new file mode 100644 index 0000000..e9b029c Binary files /dev/null and b/font.ttf differ diff --git a/levels/level1.lua b/levels/level1.lua new file mode 100644 index 0000000..dd604a6 --- /dev/null +++ b/levels/level1.lua @@ -0,0 +1,134 @@ +level1 = Class{} +local levelLoaded = false +local M = {} +function level1.update(dt) + if not levelLoaded then + shipsleft = 1 + local planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png") + planetsleft = 3 + gameStatus = "setup" + playbutts = {} + guibutts = {} + VCAM.x, VCAM.y = WINDOW_WIDTH/2, WINDOW_HEIGHT/2 + explosions = {} + shipIsHit = false + guimenu = mainMenu() + reachedGoal = false + lvlbase = base(900, 200) + levelLoaded = true + table.insert(playbutts, menu:addButton("Return to setup", function() + gameStatus = "setup" + level1.reset() + end )) + table.insert(guibutts, menu:addButton("Release brake!", function () + selectedItem = "none" + gameStatus = "play" + end + )) + table.insert(guibutts, menu:addButton("To menu", function () + level1.goBack() + end)) + table.insert(planets, planet(700, 200, 50, 0.3, planetImage)) + + end + if reachedGoal then + if levelsBeaten < 1 then + levelsBeaten = 1 + end + print("levelsBeaten is " .. levelsBeaten) + love.filesystem.write("save", levelsBeaten) + level1.goBack() + end + camera:update(dt) + lvlbase:update(dt) + --print(camera.x .. " " .. camera.y) + for i, explosion in ipairs(explosions) do + explosion:update(dt) + if explosion.killed then + table.remove(explosions, i) + gameStatus = "setup" + level1.reset() + end + end + if gameStatus == "play" then + camera.x, camera.y = firstShip.x - firstShip.height*4, firstShip.y- firstShip.width + --print(camera.x .. firstShip.x) + if shipIsHit then + if #explosions == 0 then + table.insert(explosions, explosion(firstShip.x, firstShip.y, 100, {1,1,1,1})) + end + + end + firstShip:update(dt) + + for i in ipairs(planets) do + planets[i]:update(dt) + end +else + camera:follow(VCAM.x, VCAM.y) +end + level1.GUIControl() + + +end + +function level1.draw() + love.graphics.setColor(1,1,1,1) + camera:attach() + firstShip:draw() + lvlbase:draw() + for i in ipairs(planets) do + planets[i]:draw(dt) + end + --love.graphics.rectangle("fill",VCAM.x,VCAM.y,30,30) + if shipIsHit then + for i, explosion in ipairs(explosions) do + explosion:render() + --print("exploding") + end + end + camera:detach() + + camera:draw() + + if gameStatus == "setup" then + GUIDraw("left") + elseif gameStatus == "play" then + guimenu:butt(playbutts, WINDOW_WIDTH, WINDOW_HEIGHT, 1100, WINDOW_HEIGHT-50, 40, WINDOW_WIDTH/3) + end + + + + +end +function level1.goBack() + level1.reset() + gameStatus = "setup" + firstShip.path = {} + levelLoaded = false + for k in pairs(planets) do + planets[k] = nil + end + gameState = "selectlv" +end +function level1.reset() + firstShip:reset() + for k in pairs(planets) do + planets[k] = nil + end + local planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png") + table.insert(planets, planet(700, 200, 50, 0.3, planetImage)) + shipsleft = 1 + shipIsHit = false + planetsleft = 3 +end +function level1.GUIControl() + if (love.keyboard.isDown('a') and VCAM.x > WINDOW_WIDTH/2) then + VCAM.x = VCAM.x - 10 + end + if (love.keyboard.isDown('d')) then + VCAM.x = VCAM.x + 10 + end +end +return level1 + diff --git a/levels/menu.lua b/levels/menu.lua new file mode 100644 index 0000000..48e147e --- /dev/null +++ b/levels/menu.lua @@ -0,0 +1,11 @@ +menu = Class{} +local M = {} +function menu.update(dt) + +end + +function menu.draw(dt) + menu:butt(buttons, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH/2, WINDOW_HEIGHT/2, 40, WINDOW_WIDTH/3) +end + +return menu \ No newline at end of file diff --git a/levels/practice.lua b/levels/practice.lua new file mode 100644 index 0000000..a6a752a --- /dev/null +++ b/levels/practice.lua @@ -0,0 +1,119 @@ +practice = Class{} +local levelLoaded = false +local M = {} +function practice.update(dt) + if not levelLoaded then + shipsleft = 1 + planetsleft = 10 + gameStatus = "setup" + playbutts = {} + guibutts = {} + XCAM = 0 + YCAM = 0 + explosions = {} + shipIsHit = false + guimenu = mainMenu() + table.insert(playbutts, menu:addButton("Return to setup", function() + gameStatus = "setup" + practice.reset() + end )) + table.insert(guibutts, menu:addButton("Release brake!", function () + selectedItem = "none" + gameStatus = "play" + end + )) + table.insert(guibutts, menu:addButton("To menu", function () + practice.goBack() + end + )) + levelLoaded = true + end + camera:update(dt) + + print(camera.x .. " " .. camera.y) + for i, explosion in ipairs(explosions) do + explosion:update(dt) + if explosion.killed then + table.remove(explosions, i) + gameStatus = "setup" + practice.reset() + end + end + if gameStatus == "play" then + camera.x, camera.y = firstShip.x - firstShip.height*4, firstShip.y- firstShip.width + print(camera.x .. firstShip.x) + if shipIsHit then + if #explosions == 0 then + table.insert(explosions, explosion(firstShip.x, firstShip.y, 100, {1,1,1,1})) + end + + end + firstShip:update(dt) + for i in ipairs(planets) do + planets[i]:update(dt) + end +else + camera:follow(VCAM.x, VCAM.y) +end + practice.GUIControl() + + +end + +function practice.draw() + camera:attach() + firstShip:draw() + for i in ipairs(planets) do + planets[i]:draw(dt) + end + --love.graphics.rectangle("fill",VCAM.x,VCAM.y,30,30) + if shipIsHit then + for i, explosion in ipairs(explosions) do + explosion:render() + --print("exploding") + end + end + camera:detach() + + camera:draw() + + if gameStatus == "setup" then + GUIDraw("anywhere") + elseif gameStatus == "play" then + guimenu:butt(playbutts, WINDOW_WIDTH, WINDOW_HEIGHT, 1100, WINDOW_HEIGHT-50, 40, WINDOW_WIDTH/3) + end + + + + +end +function practice.goBack() + practice.reset() + gameStatus = "setup" + levelLoaded = false + gameState = "menu" +end +function practice.reset() + firstShip:reset() + for k in pairs(planets) do + planets[k] = nil + end + shipsleft = 1 + shipIsHit = false + planetsleft = 10 +end +function practice.GUIControl() + if (love.keyboard.isDown('w')) then + VCAM.y = VCAM.y - 10 + end + if (love.keyboard.isDown('a')) then + VCAM.x = VCAM.x - 10 + end + if (love.keyboard.isDown('s')) then + VCAM.y = VCAM.y + 10 + end + if (love.keyboard.isDown('d')) then + VCAM.x = VCAM.x + 10 + end +end +return practice \ No newline at end of file diff --git a/levels/selectlv.lua b/levels/selectlv.lua new file mode 100644 index 0000000..7c08b78 --- /dev/null +++ b/levels/selectlv.lua @@ -0,0 +1,22 @@ +selectlv = Class{} +levels = {} +table.insert(levels, menu:addButton("Level 1", function () +gameState = "level1" +end )) + + + + +table.insert(levels, menu:addButton("Go Back", function () + gameState = "menu" + end )) +local M = {} +function selectlv.update(dt) + +end + +function selectlv.draw(dt) + menu:butt(levels, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH/2, WINDOW_HEIGHT/2, 40, WINDOW_WIDTH/3, "beatenGreen") +end + +return selectlv \ No newline at end of file diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..e5ac06f --- /dev/null +++ b/main.lua @@ -0,0 +1,57 @@ +gameState = "menu" +require 'src/dependencies' +math.randomseed(os.time()) +--VARIABLES +RESOLUTION_SET = 0 +isFullscreen = 0 +DIFFERENCE_X = 1 +DIFFERENCE_Y = 1 +WINDOW_WIDTH = 1280 +WINDOW_HEIGHT = 720 +OFFSET_X = 0 +OFFSET_Y = 0 + +levelsBeaten = 0 +planets = {} +buttons = {} +menu = mainMenu() + +function love.load() + testwalls = love.filesystem.load("save") + if testwalls ~= nil then + levelsBeaten = love.filesystem.load("save") + print("Save file found") + else + print("No save file found!") + end + tick.framerate = 60 + camera = Camera() + BG = love.graphics.newImage("entities/background.jpg") + simpleScale.setWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT) + firstShip = ship(-500, -500, "entities/ship/smol_red_01.png") + VCAM = VCAM(WINDOW_WIDTH/2, WINDOW_HEIGHT/2) + smallfont = love.graphics.newFont("font.ttf", 25) + --table.insert(planets, planet(100, WINDOW_HEIGHT/2-100, 1010000000, 1)) + buttonClutter() + --planet2 = planet(1000, 300, 1000000000, 20) +end + +function love.update(dt) + stateUpdate(dt) + +end + +function love.draw() + simpleScale.set() + --love.graphics.draw(BG, 0, 0) + stateDraw() + simpleScale.unSet() +end + + + +function love.mousereleased(x, y, button) + love.keyboard.mouseisReleased = true +end + + diff --git a/src/Camera.lua b/src/Camera.lua new file mode 100644 index 0000000..4d6a7da --- /dev/null +++ b/src/Camera.lua @@ -0,0 +1,369 @@ +--[[ +MIT License + +Copyright (c) 2017 SSYGEN + +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 function lerp(a, b, x) return a + (b - a)*x end +local function csnap(v, x) return math.ceil(v/x)*x - x/2 end + +-- Shake according to https://jonny.morrill.me/en/blog/gamedev-how-to-implement-a-camera-shake-effect/ +local function newShake(amplitude, duration, frequency) + local self = { + amplitude = amplitude or 0, + duration = duration or 0, + frequency = frequency or 60, + samples = {}, + start_time = love.timer.getTime()*1000, + t = 0, + shaking = true, + } + + local sample_count = (self.duration/1000)*self.frequency + for i = 1, sample_count do self.samples[i] = 2*love.math.random()-1 end + + return self +end + +local function updateShake(self, dt) + self.t = love.timer.getTime()*1000 - self.start_time + if self.t > self.duration then self.shaking = false end +end + +local function shakeNoise(self, s) + if s >= #self.samples then return 0 end + return self.samples[s] or 0 +end + +local function shakeDecay(self, t) + if t > self.duration then return 0 end + return (self.duration - t)/self.duration +end + +local function getShakeAmplitude(self, t) + if not t then + if not self.shaking then return 0 end + t = self.t + end + + local s = (t/1000)*self.frequency + local s0 = math.floor(s) + local s1 = s0 + 1 + local k = shakeDecay(self, t) + return self.amplitude*(shakeNoise(self, s0) + (s - s0)*(shakeNoise(self, s1) - shakeNoise(self, s0)))*k +end + +-- Camera +local Camera = {} +Camera.__index = Camera + +local function new(x, y, w, h, scale, rotation) + return setmetatable({ + x = x or (w or love.graphics.getWidth())/2, y = y or (h or love.graphics.getHeight())/2, + mx = x or (w or love.graphics.getWidth())/2, my = y or (h or love.graphics.getHeight())/2, + screen_x = x or (w or love.graphics.getWidth())/2, screen_y = y or (h or love.graphics.getHeight())/2, + w = w or love.graphics.getWidth(), h = h or love.graphics.getHeight(), + scale = scale or 1, + rotation = rotation or 0, + horizontal_shakes = {}, vertical_shakes = {}, + target_x = nil, target_y = nil, + scroll_x = 0, scroll_y = 0, + last_target_x = nil, last_target_y = nil, + follow_lerp_x = 1, follow_lerp_y = 1, + follow_lead_x = 0, follow_lead_y = 0, + deadzone = nil, bound = nil, + draw_deadzone = false, + flash_duration = 1, flash_timer = 0, flash_color = {0, 0, 0, 1}, + last_horizontal_shake_amount = 0, last_vertical_shake_amount = 0, + fade_duration = 1, fade_timer = 0, fade_color = {0, 0, 0, 0}, + }, Camera) +end + +function Camera:attach() + love.graphics.push() + love.graphics.translate(self.w/2, self.h/2) + love.graphics.scale(self.scale) + love.graphics.rotate(self.rotation) + love.graphics.translate(-self.x, -self.y) +end + +function Camera:detach() + love.graphics.pop() +end + +function Camera:move(dx, dy) + self.x, self.y = self.x + dx, self.y + dy +end + +function Camera:toWorldCoords(x, y) + local c, s = math.cos(self.rotation), math.sin(self.rotation) + x, y = (x - self.w/2)/self.scale, (y - self.h/2)/self.scale + x, y = c*x - s*y, s*x + c*y + return x + self.x, y + self.y +end + +function Camera:toCameraCoords(x, y) + local c, s = math.cos(self.rotation), math.sin(self.rotation) + x, y = x - self.x, y - self.y + x, y = c*x - s*y, s*x + c*y + return x*self.scale + self.w/2, y*self.scale + self.h/2 +end + +function Camera:getMousePosition() + return self:toWorldCoords(love.mouse.getPosition()) +end + +function Camera:shake(intensity, duration, frequency, axes) + if not axes then axes = 'XY' end + axes = string.upper(axes) + + if string.find(axes, 'X') then table.insert(self.horizontal_shakes, newShake(intensity, duration*1000, frequency)) end + if string.find(axes, 'Y') then table.insert(self.vertical_shakes, newShake(intensity, duration*1000, frequency)) end +end + +function Camera:update(dt) + self.mx, self.my = self:toWorldCoords(love.mouse.getPosition()) + + -- Flash -- + if self.flashing then + self.flash_timer = self.flash_timer + dt + if self.flash_timer > self.flash_duration then + self.flash_timer = 0 + self.flashing = false + end + end + + -- Fade -- + if self.fading then + self.fade_timer = self.fade_timer + dt + self.fade_color = { + lerp(self.base_fade_color[1], self.target_fade_color[1], self.fade_timer/self.fade_duration), + lerp(self.base_fade_color[2], self.target_fade_color[2], self.fade_timer/self.fade_duration), + lerp(self.base_fade_color[3], self.target_fade_color[3], self.fade_timer/self.fade_duration), + lerp(self.base_fade_color[4], self.target_fade_color[4], self.fade_timer/self.fade_duration), + } + if self.fade_timer > self.fade_duration then + self.fade_timer = 0 + self.fading = false + if self.fade_action then self.fade_action() end + end + end + + -- Shake -- + local horizontal_shake_amount, vertical_shake_amount = 0, 0 + for i = #self.horizontal_shakes, 1, -1 do + updateShake(self.horizontal_shakes[i], dt) + horizontal_shake_amount = horizontal_shake_amount + getShakeAmplitude(self.horizontal_shakes[i]) + if not self.horizontal_shakes[i].shaking then table.remove(self.horizontal_shakes, i) end + end + for i = #self.vertical_shakes, 1, -1 do + updateShake(self.vertical_shakes[i], dt) + vertical_shake_amount = vertical_shake_amount + getShakeAmplitude(self.vertical_shakes[i]) + if not self.vertical_shakes[i].shaking then table.remove(self.vertical_shakes, i) end + end + self.x, self.y = self.x - self.last_horizontal_shake_amount, self.y - self.last_vertical_shake_amount + self:move(horizontal_shake_amount, vertical_shake_amount) + self.last_horizontal_shake_amount, self.last_vertical_shake_amount = horizontal_shake_amount, vertical_shake_amount + + -- Follow -- + if not self.target_x and not self.target_y then return end + + -- Set follow style deadzones + if self.follow_style == 'LOCKON' then + local w, h = self.w/16, self.w/16 + self:setDeadzone((self.w - w)/2, (self.h - h)/2, w, h) + + elseif self.follow_style == 'PLATFORMER' then + local w, h = self.w/8, self.h/3 + self:setDeadzone((self.w - w)/2, (self.h - h)/2 - h*0.25, w, h) + + elseif self.follow_style == 'TOPDOWN' then + local s = math.max(self.w, self.h)/4 + self:setDeadzone((self.w - s)/2, (self.h - s)/2, s, s) + + elseif self.follow_style == 'TOPDOWN_TIGHT' then + local s = math.max(self.w, self.h)/8 + self:setDeadzone((self.w - s)/2, (self.h - s)/2, s, s) + + elseif self.follow_style == 'SCREEN_BY_SCREEN' then + self:setDeadzone(0, 0, 0, 0) + + elseif self.follow_style == 'NO_DEADZONE' then + self.deadzone = nil + end + + -- No deadzone means we just track the target with no lerp + if not self.deadzone then + self.x, self.y = self.target_x, self.target_y + if self.bound then + self.x = math.min(math.max(self.x, self.bounds_min_x + self.w/2), self.bounds_max_x - self.w/2) + self.y = math.min(math.max(self.y, self.bounds_min_y + self.h/2), self.bounds_max_y - self.h/2) + end + return + end + + -- Convert appropriate variables to camera coordinates since the deadzone is applied in terms of the camera and not the world + local dx1, dy1, dx2, dy2 = self.deadzone_x, self.deadzone_y, self.deadzone_x + self.deadzone_w, self.deadzone_y + self.deadzone_h + local scroll_x, scroll_y = 0, 0 + local target_x, target_y = self:toCameraCoords(self.target_x, self.target_y) + local x, y = self:toCameraCoords(self.x, self.y) + + -- Screen by screen follow mode needs to be handled a bit differently + if self.follow_style == 'SCREEN_BY_SCREEN' then + -- Don't change self.screen_x/y if already at the boundaries + if self.bound then + if self.x > self.bounds_min_x + self.w/2 and target_x < 0 then self.screen_x = csnap(self.screen_x - self.w/self.scale, self.w/self.scale) end + if self.x < self.bounds_max_x - self.w/2 and target_x >= self.w then self.screen_x = csnap(self.screen_x + self.w/self.scale, self.w/self.scale) end + if self.y > self.bounds_min_y + self.h/2 and target_y < 0 then self.screen_y = csnap(self.screen_y - self.h/self.scale, self.h/self.scale) end + if self.y < self.bounds_max_y - self.h/2 and target_y >= self.h then self.screen_y = csnap(self.screen_y + self.h/self.scale, self.h/self.scale) end + -- Move to the next screen if the target is outside the screen boundaries + else + if target_x < 0 then self.screen_x = csnap(self.screen_x - self.w/self.scale, self.w/self.scale) end + if target_x >= self.w then self.screen_x = csnap(self.screen_x + self.w/self.scale, self.w/self.scale) end + if target_y < 0 then self.screen_y = csnap(self.screen_y - self.h/self.scale, self.h/self.scale) end + if target_y >= self.h then self.screen_y = csnap(self.screen_y + self.h/self.scale, self.h/self.scale) end + end + self.x = lerp(self.x, self.screen_x, self.follow_lerp_x) + self.y = lerp(self.y, self.screen_y, self.follow_lerp_y) + + -- Apply bounds + if self.bound then + self.x = math.min(math.max(self.x, self.bounds_min_x + self.w/2), self.bounds_max_x - self.w/2) + self.y = math.min(math.max(self.y, self.bounds_min_y + self.h/2), self.bounds_max_y - self.h/2) + end + + -- All other follow modes + else + -- Figure out how much the camera needs to scroll + if target_x < x + (dx1 + dx2 - x) then + local d = target_x - dx1 + if d < 0 then scroll_x = d end + end + if target_x > x - (dx1 + dx2 - x) then + local d = target_x - dx2 + if d > 0 then scroll_x = d end + end + if target_y < y + (dy1 + dy2 - y) then + local d = target_y - dy1 + if d < 0 then scroll_y = d end + end + if target_y > y - (dy1 + dy2 - y) then + local d = target_y - dy2 + if d > 0 then scroll_y = d end + end + + -- Apply lead + if not self.last_target_x and not self.last_target_y then self.last_target_x, self.last_target_y = self.target_x, self.target_y end + scroll_x = scroll_x + (self.target_x - self.last_target_x)*self.follow_lead_x + scroll_y = scroll_y + (self.target_y - self.last_target_y)*self.follow_lead_y + self.last_target_x, self.last_target_y = self.target_x, self.target_y + + -- Scroll towards target with lerp + self.x = lerp(self.x, self.x + scroll_x, self.follow_lerp_x) + self.y = lerp(self.y, self.y + scroll_y, self.follow_lerp_y) + + -- Apply bounds + if self.bound then + self.x = math.min(math.max(self.x, self.bounds_min_x + self.w/2), self.bounds_max_x - self.w/2) + self.y = math.min(math.max(self.y, self.bounds_min_y + self.h/2), self.bounds_max_y - self.h/2) + end + end +end + +function Camera:draw() + if self.draw_deadzone and self.deadzone then + local n = love.graphics.getLineWidth() + love.graphics.setLineWidth(2) + love.graphics.line(self.deadzone_x - 1, self.deadzone_y, self.deadzone_x + 6, self.deadzone_y) + love.graphics.line(self.deadzone_x, self.deadzone_y, self.deadzone_x, self.deadzone_y + 6) + love.graphics.line(self.deadzone_x - 1, self.deadzone_y + self.deadzone_h, self.deadzone_x + 6, self.deadzone_y + self.deadzone_h) + love.graphics.line(self.deadzone_x, self.deadzone_y + self.deadzone_h, self.deadzone_x, self.deadzone_y + self.deadzone_h - 6) + love.graphics.line(self.deadzone_x + self.deadzone_w + 1, self.deadzone_y + self.deadzone_h, self.deadzone_x + self.deadzone_w - 6, self.deadzone_y + self.deadzone_h) + love.graphics.line(self.deadzone_x + self.deadzone_w, self.deadzone_y + self.deadzone_h, self.deadzone_x + self.deadzone_w, self.deadzone_y + self.deadzone_h - 6) + love.graphics.line(self.deadzone_x + self.deadzone_w + 1, self.deadzone_y, self.deadzone_x + self.deadzone_w - 6, self.deadzone_y) + love.graphics.line(self.deadzone_x + self.deadzone_w, self.deadzone_y, self.deadzone_x + self.deadzone_w, self.deadzone_y + 6) + love.graphics.setLineWidth(n) + end + + if self.flashing then + local r, g, b, a = love.graphics.getColor() + love.graphics.setColor(self.flash_color) + love.graphics.rectangle('fill', 0, 0, self.w, self.h) + love.graphics.setColor(r, g, b, a) + end + + local r, g, b, a = love.graphics.getColor() + love.graphics.setColor(self.fade_color) + love.graphics.rectangle('fill', 0, 0, self.w, self.h) + love.graphics.setColor(r, g, b, a) +end + +function Camera:follow(x, y) + self.target_x, self.target_y = x, y +end + +function Camera:setDeadzone(x, y, w, h) + self.deadzone = true + self.deadzone_x = x + self.deadzone_y = y + self.deadzone_w = w + self.deadzone_h = h +end + +function Camera:setBounds(x, y, w, h) + self.bound = true + self.bounds_min_x = x + self.bounds_min_y = y + self.bounds_max_x = x + w + self.bounds_max_y = y + h +end + +function Camera:setFollowStyle(follow_style) + self.follow_style = follow_style +end + +function Camera:setFollowLerp(x, y) + self.follow_lerp_x = x + self.follow_lerp_y = y or x +end + +function Camera:setFollowLead(x, y) + self.follow_lead_x = x + self.follow_lead_y = y or x +end + +function Camera:flash(duration, color) + self.flash_duration = duration + self.flash_color = color or self.flash_color + self.flash_timer = 0 + self.flashing = true +end + +function Camera:fade(duration, color, action) + self.fade_duration = duration + self.base_fade_color = self.fade_color + self.target_fade_color = color + self.fade_timer = 0 + self.fade_action = action + self.fading = true +end + +return setmetatable({new = new}, {__call = function(_, ...) return new(...) end}) \ No newline at end of file diff --git a/src/GUI.lua b/src/GUI.lua new file mode 100644 index 0000000..ee7b29e --- /dev/null +++ b/src/GUI.lua @@ -0,0 +1,221 @@ +selectedItem = "none" +local planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png") + + +function GUIDraw(mode) + --MAIN + love.graphics.setColor(1,1,1,1) + love.graphics.rectangle("fill", WINDOW_WIDTH*0.7-3, 0, WINDOW_WIDTH*0.3-3, WINDOW_HEIGHT) + love.graphics.setColor(0,0,0,1) + local menuX = WINDOW_WIDTH*0.7 + local menuW = WINDOW_WIDTH*0.3 + local menuY = 3 + love.graphics.rectangle("fill", WINDOW_WIDTH*0.7, 3, WINDOW_WIDTH*0.3, WINDOW_HEIGHT-6) + love.graphics.setFont(smallfont) + love.graphics.setColor(1,1,1,1) + local textW = smallfont:getWidth("Control Panel") + love.graphics.print("Control Panel",menuX + menuW/2-textW/2,menuY+10) + --MAIN + + --SHIP + local shipImage = love.graphics.newImage("entities/ship/smol_red_01.png") + GUIButton(shipsleft, shipImage, menuX + 60, menuY+WINDOW_HEIGHT*0.2, function() selectedItem = "ship" end, 1, 1, {1,1,1,1}, 1.57) + --SHIP + --PLANET + GUIButton(planetsleft, planetImage, menuX + 60, menuY+WINDOW_HEIGHT*0.4, function() selectedItem = "planet" end, 0.5, 0.5, {1,1,1,1}, 1.57) + --PLANET + + + --PLACING + local mx, my = love.mouse.getPosition() + local vmx, vmy = camera:getMousePosition() + local mx = mx * DIFFERENCE_X + local my = my * DIFFERENCE_Y + if mode == "anywhere" then + love.graphics.setColor(1,1,1,0.5) + if selectedItem == "ship" and mx < menuX then + local shipW = shipImage:getWidth() + local shipH = shipImage:getHeight() + love.graphics.draw(shipImage,mx,my, 1.5708, 1, 1, shipW/2, shipH/2) + if love.keyboard.mouseisReleased then + love.keyboard.mouseisReleased = false + firstShip.x = vmx + firstShip.y = vmy + shipsleft = shipsleft - 1 + end + if shipsleft == 0 then + selectedItem = "none" + end + end + elseif mode == "left" then + love.graphics.setColor(1,1,1,0.5) + if selectedItem == "ship" and mx < menuX then + local shipW = shipImage:getWidth() + local shipH = shipImage:getHeight() + love.graphics.draw(shipImage,10,my, 1.5708, 1, 1, shipW/2, shipH/2) + if love.keyboard.mouseisReleased then + love.keyboard.mouseisReleased = false + firstShip.x = 250 + firstShip.y = vmy + shipsleft = shipsleft - 1 + end + if shipsleft == 0 then + selectedItem = "none" + end + end + end + local dx, dy = camera:toCameraCoords(firstShip.x, firstShip.y) + if VCAM.x - WINDOW_WIDTH/2+250 > firstShip.x and shipsleft == 0 then + love.graphics.setColor(1,0,0,1) + love.graphics.rectangle("fill", 0, dy-firstShip.width/2, 10, firstShip.width) + end + if VCAM.y - WINDOW_HEIGHT/2+50 > firstShip.y and shipsleft == 0 then + love.graphics.setColor(1,0,0,1) + love.graphics.rectangle("fill", dx-firstShip.height/2, 0, firstShip.height, 10) + end + if VCAM.y + WINDOW_HEIGHT/2+50 < firstShip.y and shipsleft == 0 then + love.graphics.setColor(1,0,0,1) + love.graphics.rectangle("fill", dx-firstShip.height/2, WINDOW_HEIGHT-10, firstShip.height, 10) + end + if VCAM.x + WINDOW_WIDTH/2-150< firstShip.x and shipsleft == 0 then + love.graphics.setColor(1,0,0,1) + love.graphics.rectangle("fill", menuX-10, dy-firstShip.width/2, 10, firstShip.width) + end + + for k in ipairs(planets) do + local dx, dy = camera:toCameraCoords(planets[k].x, planets[k].y) + if VCAM.x - WINDOW_WIDTH/2+250 > planets[k].x then + love.graphics.setColor(0,0,1,1) + love.graphics.rectangle("fill", 0, dy-planets[k].w*0.3/2, 10, planets[k].w*0.3) + end + if VCAM.y - WINDOW_HEIGHT/2+50 > planets[k].y then + love.graphics.setColor(0,0,1,1) + love.graphics.rectangle("fill", dx-planets[k].w*0.3/2, 0, planets[k].w*0.3, 10) + end + if VCAM.y + WINDOW_HEIGHT/2+50 < planets[k].y then + love.graphics.setColor(0,0,1,1) + love.graphics.rectangle("fill", dx-planets[k].w*0.3/2, WINDOW_HEIGHT-10, planets[k].w*0.3, 10) + end + if VCAM.x + WINDOW_WIDTH/2-150< planets[k].x then + love.graphics.setColor(0,0,1,1) + love.graphics.rectangle("fill", menuX-10, dy-planets[k].w*0.3/2, 10, planets[k].w*0.3) + end + end + if lvlbase ~= nil then + local dx, dy = camera:toCameraCoords(lvlbase.x, lvlbase.y) + print("YESYEYSYSYADSYADYASD") + if VCAM.x - WINDOW_WIDTH/2+250 > lvlbase.x then + love.graphics.setColor(0,1,0,1) + love.graphics.rectangle("fill", 0, dy-lvlbase.w/2, 10, lvlbase.w) + end + if VCAM.y - WINDOW_HEIGHT/2+50 > lvlbase.y then + love.graphics.setColor(0,1,0,1) + love.graphics.rectangle("fill", dx-lvlbase.w/2, 0, lvlbase.w, 10) + end + if VCAM.y + WINDOW_HEIGHT/2+50 < lvlbase.y then + love.graphics.setColor(0,1,0,1) + love.graphics.rectangle("fill", dx-lvlbase.w/2, WINDOW_HEIGHT-10, lvlbase.w, 10) + end + if VCAM.x + WINDOW_WIDTH/2-150< lvlbase.x then + love.graphics.setColor(0,1,0,1) + love.graphics.rectangle("fill", menuX-10, dy-lvlbase.w/2, 10, lvlbase.w) + end + end + if selectedItem == "planet" and mx < menuX then + local shipW = planetImage:getWidth() + local shipH = planetImage:getHeight() + love.graphics.draw(planetImage,mx,my,0, 0.3, 0.3, shipW/2, shipH/2) + if love.keyboard.mouseisReleased then + love.keyboard.mouseisReleased = false + table.insert(planets, planet(vmx, vmy, 1000000000, 0.3, planetImage)) + planetImage = love.graphics.newImage("entities/planet/planet" .. math.random(1, 18) .. ".png") + planetsleft = planetsleft-1 + end + if planetsleft == 0 then + selectedItem = "none" + end + end + if selectedItem == "eraser" then + local hot = (vmx > firstShip.x-firstShip.height/2 and vmx < firstShip.x+firstShip.height and vmy > firstShip.y-firstShip.width/2 and vmy < firstShip.y - firstShip.width/2 + firstShip.width) + if hot then + firstShip.color = {1,0,0,1} + print("hot") + else + firstShip.color = {1,1,1,1} + print(mx .. " " .. my .. " " .. firstShip.x .. " " .. firstShip.y .. " " .. firstShip.width .. firstShip.height) + end + local pressed = love.keyboard.mouseisReleased + if location == "android" then + pressed = love.mouse.isDown(1) + end + if pressed and hot then + love.keyboard.mouseisReleased = false + firstShip.x = -9000 + shipsleft = shipsleft + 1 + end + + + for j in ipairs(planets) do + local hot = (vmx > planets[j].x-planets[j].w*0.3/2 and vmx < planets[j].x+planets[j].w*0.3 and vmy > planets[j].y-planets[j].w*0.3/2 and vmy < planets[j].y + planets[j].w*0.3) + if hot then + planets[j].color = {1,0,0,1} + print("hot") + else + planets[j].color = {1,1,1,1} + --print(mx .. " " .. my .. " " .. firstShip.x .. " " .. firstShip.y .. " " .. firstShip.width .. firstShip.height) + end + local pressed = love.keyboard.mouseisReleased + if location == "android" then + pressed = love.mouse.isDown(1) + end + if pressed and hot then + love.keyboard.mouseisReleased = false + table.remove(planets, j) + planetsleft = planetsleft + 1 + break + end + end + end + --PLACING + + + --REMOVE TOOL + trashbin = love.graphics.newImage("entities/trashbin.png") + GUIButton("inf", trashbin, menuX + 60, menuY+WINDOW_HEIGHT*0.6, function() selectedItem = "eraser" end, 1, 1, {1,1,1,1}, 0) + --REMOVE TOOL + + --START BUTTON + if shipsleft == 0 then + guimenu:butt(guibutts, WINDOW_WIDTH, WINDOW_HEIGHT, menuX + 200, WINDOW_HEIGHT-100, 40, WINDOW_WIDTH/3.7) + end + --START BUTTON + love.window.setTitle(selectedItem) +end + + +function GUIButton(num, shipImage, x, y, fn, sx, sy, color, r) + love.graphics.setColor(unpack(color)) + local shipW = shipImage:getWidth() + local shipH = shipImage:getHeight() + + local mx, my = love.mouse.getPosition() + local vmx, vmy = camera:getMousePosition() + local mx = mx * DIFFERENCE_X + local my = my * DIFFERENCE_Y + local hot = (mx > x-shipW/2*sx and mx < x-shipW/2*sx + shipW*sx and my > y-shipH/2*sy and my < y -shipH/2*sy + shipH*sy) + if (hot) then + love.graphics.setColor(1,0,0,0.5) + --love.graphics.rectangle("fill", x, y, shipW, shipH) + end + local pressed = love.keyboard.mouseisReleased + if location == "android" then + pressed = love.mouse.isDown(1) + end + if pressed and hot then + love.keyboard.mouseisReleased = false + fn() + end + love.graphics.draw(shipImage,x,y, r, sx, sy, shipW/2, shipH/2) + love.graphics.print("x" .. num,x+10,y) + love.graphics.setColor(1,1,1,1) +end \ No newline at end of file diff --git a/src/class.lua b/src/class.lua new file mode 100644 index 0000000..484b776 --- /dev/null +++ b/src/class.lua @@ -0,0 +1,94 @@ +--[[ +Copyright (c) 2010-2013 Matthias Richter +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. +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. +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 function include_helper(to, from, seen) + if from == nil then + return to + elseif type(from) ~= 'table' then + return from + elseif seen[from] then + return seen[from] + end + + seen[from] = to + for k,v in pairs(from) do + k = include_helper({}, k, seen) -- keys might also be tables + if to[k] == nil then + to[k] = include_helper({}, v, seen) + end + end + return to +end + +-- deeply copies `other' into `class'. keys in `other' that are already +-- defined in `class' are omitted +local function include(class, other) + return include_helper(class, other, {}) +end + +-- returns a deep copy of `other' +local function clone(other) + return setmetatable(include({}, other), getmetatable(other)) +end + +local function new(class) + -- mixins + class = class or {} -- class can be nil + local inc = class.__includes or {} + if getmetatable(inc) then inc = {inc} end + + for _, other in ipairs(inc) do + if type(other) == "string" then + other = _G[other] + end + include(class, other) + end + + -- class implementation + class.__index = class + class.init = class.init or class[1] or function() end + class.include = class.include or include + class.clone = class.clone or clone + + -- constructor call + return setmetatable(class, {__call = function(c, ...) + local o = setmetatable({}, c) + o:init(...) + return o + end}) +end + +-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons). +if class_commons ~= false and not common then + common = {} + function common.class(name, prototype, parent) + return new{__includes = {prototype, parent}} + end + function common.instance(class, ...) + return class(...) + end +end + + +-- the module +return setmetatable({new = new, include = include, clone = clone}, + {__call = function(_,...) return new(...) end}) \ No newline at end of file diff --git a/src/dependencies.lua b/src/dependencies.lua new file mode 100644 index 0000000..b72612c --- /dev/null +++ b/src/dependencies.lua @@ -0,0 +1,17 @@ +Class = require 'src/class' +require 'src/simpleScale' +require 'src/fullScreener' +require 'src/mainMenu' +require 'src/pongDisplayControl' +require 'entities/ship/ship' +require 'entities/planet/planet' +require 'buttonClutter' +require 'explosion' +require 'src/GUI' +require 'stateMachine' +require 'entities/base/base' +require 'entities/camera/VCAM' +tick = require 'src/tick' +utf8 = require("utf8") +serialize = require 'src/ser' +Camera = require 'src/Camera' \ No newline at end of file diff --git a/src/fullScreener.lua b/src/fullScreener.lua new file mode 100644 index 0000000..bcd2d4d --- /dev/null +++ b/src/fullScreener.lua @@ -0,0 +1,39 @@ +fullScreener = Class{} +function fullScreener:init(a,b,c,d,e,f) + self.a = a + self.b = b + self.c = c + self.d = d + self.e = e + self.f = f +end +function fullScreener:toggle(vh, vw) + self.a = self.a + 1 + if (self.a > 1) then + self.a = 0 + end + if (self.a == 0 ) then + if (self.b == 1) then + self.c = 1 + self.d = 1 + self.e = 0 + self.f = 0 + simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT,{fullscreen = false}) + self.b = 0 + end + + end + if (self.a == 1) then + if (self.b == 0) then + simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = true}) + local newWidth = love.graphics.getWidth() + local newHeight = love.graphics.getHeight() + self.c = VIRTUAL_WIDTH / newWidth + self.d = VIRTUAL_HEIGHT / newHeight + self.e = math.fmod(newWidth * self.d, VIRTUAL_WIDTH) / 2 + self.f = math.fmod(newHeight * self.d, VIRTUAL_HEIGHT) / 2 + self.b = 1 + + end +end +end diff --git a/src/mainMenu.lua b/src/mainMenu.lua new file mode 100644 index 0000000..7cc2bee --- /dev/null +++ b/src/mainMenu.lua @@ -0,0 +1,53 @@ +mainMenu = Class{} +function mainMenu:butt(buttons, VIRTUAL_WIDTH, VIRTUAL_HEIGHT, locationx, locationy, ev_BUTTON_HEIGHT, ev_button_width, arg) + local margin = 16 + local hot = false + local cursor_y = 0 + local total_height = (ev_BUTTON_HEIGHT + margin) * #buttons + local ev_bx, ev_by + for i, button in ipairs(buttons) do + button.last = button.now + ev_bx = locationx - (ev_button_width * 0.5) + ev_by = locationy - (total_height * 0.5) + cursor_y + local color = {255, 255, 255, 255} + local mx, my = love.mouse.getPosition() + local mx = mx * DIFFERENCE_X + local my = my * DIFFERENCE_Y + local hot = (mx > ev_bx and mx < ev_bx + ev_button_width and my > ev_by and my < ev_by + ev_BUTTON_HEIGHT) and i + if (hot == i) then + color = {10, 10, 0, 255} + end + button.now = love.keyboard.mouseisReleased + if location == "android" then + button.now = love.mouse.isDown(1) + end + if button.now and hot == i then + love.keyboard.mouseisReleased = false + button.fn() + break + end + if arg == "beatenGreen" then + if i <= levelsBeaten then + color = {0,1,0,1} + end + end + love.graphics.setColor(unpack(color)) + love.graphics.rectangle("fill", ev_bx,ev_by, ev_button_width, ev_BUTTON_HEIGHT) + love.graphics.setColor(0, 0, 0, 255) + local textW = smallfont:getWidth(button.text) + local textH = smallfont:getHeight(button.text) + love.graphics.print(button.text, smallfont, ev_bx + ev_button_width*0.5 - textW*0.5, ev_by+textH*0.5) + love.graphics.setColor(255, 255, 255, 255) + cursor_y = cursor_y + (ev_BUTTON_HEIGHT + margin) + + end + +end +function mainMenu:addButton(text, fn) + return { + text = text, + fn = fn, + now = false, + last = false + } +end diff --git a/src/pongDisplayControl.lua b/src/pongDisplayControl.lua new file mode 100644 index 0000000..ec92bf5 --- /dev/null +++ b/src/pongDisplayControl.lua @@ -0,0 +1,27 @@ +function resolutionChanger() + if (RESOLUTION_SET > 1) then + RESOLUTION_SET = 0 + end + if (RESOLUTION_SET == 0) then + if (isFullscreen == 1) then + DIFFERENCE_X = 1 + DIFFERENCE_Y = 1 + OFFSET_X = 0 + OFFSET_Y = 0 + simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = false}) + isFullscreen = 0 + end + end + if (RESOLUTION_SET == 1) then + if (isFullscreen == 0) then + simpleScale.updateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, {fullscreen = true}) + local newWidth = love.graphics.getWidth() + local newHeight = love.graphics.getHeight() + DIFFERENCE_X = VIRTUAL_WIDTH / newWidth + DIFFERENCE_Y = VIRTUAL_HEIGHT / newHeight + OFFSET_X = math.fmod(newWidth, VIRTUAL_WIDTH) / 2 + OFFSET_Y = math.fmod(newHeight, VIRTUAL_HEIGHT) / 2 + isFullscreen = 1 + end + end +end \ No newline at end of file diff --git a/src/push.lua b/src/push.lua new file mode 100644 index 0000000..5c94d9f --- /dev/null +++ b/src/push.lua @@ -0,0 +1,272 @@ +local love11 = love.getVersion() == 11 +local getDPI = love11 and love.window.getDPIScale or love.window.getPixelScale +local windowUpdateMode = love11 and love.window.updateMode or function(width, height, settings) + local _, _, flags = love.window.getMode() + for k, v in pairs(settings) do flags[k] = v end + love.window.setMode(width, height, flags) +end + +local push = { + + defaults = { + fullscreen = false, + resizable = false, + pixelperfect = false, + highdpi = true, + canvas = true, + stencil = true + } + +} +setmetatable(push, push) + +function push:applySettings(settings) + for k, v in pairs(settings) do + self["_" .. k] = v + end +end + +function push:resetSettings() return self:applySettings(self.defaults) end + +function push:setupScreen(WWIDTH, WHEIGHT, RWIDTH, RHEIGHT, settings) + + settings = settings or {} + + self._WWIDTH, self._WHEIGHT = WWIDTH, WHEIGHT + self._RWIDTH, self._RHEIGHT = RWIDTH, RHEIGHT + + self:applySettings(self.defaults) --set defaults first + self:applySettings(settings) --then fill with custom settings + + windowUpdateMode(self._RWIDTH, self._RHEIGHT, { + fullscreen = self._fullscreen, + resizable = self._resizable, + highdpi = self._highdpi + }) + + self:initValues() + + if self._canvas then + self:setupCanvas({ "default" }) --setup canvas + end + + self._borderColor = {0, 0, 0} + + self._drawFunctions = { + ["start"] = self.start, + ["end"] = self.finish + } + + return self +end + +function push:setupCanvas(canvases) + table.insert(canvases, { name = "_render", private = true }) --final render + + self._canvas = true + self.canvases = {} + + for i = 1, #canvases do + push:addCanvas(canvases[i]) + end + + return self +end +function push:addCanvas(params) + table.insert(self.canvases, { + name = params.name, + private = params.private, + shader = params.shader, + canvas = love.graphics.newCanvas(self._WWIDTH, self._WHEIGHT), + stencil = params.stencil or self._stencil + }) +end + +function push:setCanvas(name) + if not self._canvas then return true end + return love.graphics.setCanvas(self:getCanvasTable(name).canvas) +end +function push:getCanvasTable(name) + for i = 1, #self.canvases do + if self.canvases[i].name == name then + return self.canvases[i] + end + end +end +function push:setShader(name, shader) + if not shader then + self:getCanvasTable("_render").shader = name + else + self:getCanvasTable(name).shader = shader + end +end + +function push:initValues() + self._PSCALE = (not love11 and self._highdpi) and getDPI() or 1 + + self._SCALE = { + x = self._RWIDTH/self._WWIDTH * self._PSCALE, + y = self._RHEIGHT/self._WHEIGHT * self._PSCALE + } + + if self._stretched then --if stretched, no need to apply offset + self._OFFSET = {x = 0, y = 0} + else + local scale = math.min(self._SCALE.x, self._SCALE.y) + if self._pixelperfect then scale = math.floor(scale) end + + self._OFFSET = {x = (self._SCALE.x - scale) * (self._WWIDTH/2), y = (self._SCALE.y - scale) * (self._WHEIGHT/2)} + self._SCALE.x, self._SCALE.y = scale, scale --apply same scale to X and Y + end + + self._GWIDTH = self._RWIDTH * self._PSCALE - self._OFFSET.x * 2 + self._GHEIGHT = self._RHEIGHT * self._PSCALE - self._OFFSET.y * 2 +end + +function push:apply(operation, shader) + self._drawFunctions[operation](self, shader) +end + +function push:start() + if self._canvas then + love.graphics.push() + love.graphics.setCanvas({ self.canvases[1].canvas, stencil = self.canvases[1].stencil }) + + else + love.graphics.translate(self._OFFSET.x, self._OFFSET.y) + love.graphics.setScissor(self._OFFSET.x, self._OFFSET.y, self._WWIDTH*self._SCALE.x, self._WHEIGHT*self._SCALE.y) + love.graphics.push() + love.graphics.scale(self._SCALE.x, self._SCALE.y) + end +end + +function push:applyShaders(canvas, shaders) + local _shader = love.graphics.getShader() + if #shaders <= 1 then + love.graphics.setShader(shaders[1]) + love.graphics.draw(canvas) + else + local _canvas = love.graphics.getCanvas() + + local _tmp = self:getCanvasTable("_tmp") + if not _tmp then --create temp canvas only if needed + self:addCanvas({ name = "_tmp", private = true, shader = nil }) + _tmp = self:getCanvasTable("_tmp") + end + + love.graphics.push() + love.graphics.origin() + local outputCanvas + for i = 1, #shaders do + local inputCanvas = i % 2 == 1 and canvas or _tmp.canvas + outputCanvas = i % 2 == 0 and canvas or _tmp.canvas + love.graphics.setCanvas(outputCanvas) + love.graphics.clear() + love.graphics.setShader(shaders[i]) + love.graphics.draw(inputCanvas) + love.graphics.setCanvas(inputCanvas) + end + love.graphics.pop() + + love.graphics.setCanvas(_canvas) + love.graphics.draw(outputCanvas) + end + love.graphics.setShader(_shader) +end + +function push:finish(shader) + love.graphics.setBackgroundColor(unpack(self._borderColor)) + if self._canvas then + local _render = self:getCanvasTable("_render") + + love.graphics.pop() + + local white = love11 and 1 or 255 + love.graphics.setColor(white, white, white) + + --draw canvas + love.graphics.setCanvas(_render.canvas) + for i = 1, #self.canvases do --do not draw _render yet + local _table = self.canvases[i] + if not _table.private then + local _canvas = _table.canvas + local _shader = _table.shader + self:applyShaders(_canvas, type(_shader) == "table" and _shader or { _shader }) + end + end + love.graphics.setCanvas() + + --draw render + love.graphics.translate(self._OFFSET.x, self._OFFSET.y) + local shader = shader or _render.shader + love.graphics.push() + love.graphics.scale(self._SCALE.x, self._SCALE.y) + self:applyShaders(_render.canvas, type(shader) == "table" and shader or { shader }) + love.graphics.pop() + + --clear canvas + for i = 1, #self.canvases do + love.graphics.setCanvas(self.canvases[i].canvas) + love.graphics.clear() + end + + love.graphics.setCanvas() + love.graphics.setShader() + else + love.graphics.pop() + love.graphics.setScissor() + end +end + +function push:setBorderColor(color, g, b) + self._borderColor = g and {color, g, b} or color +end + +function push:toGame(x, y) + x, y = x - self._OFFSET.x, y - self._OFFSET.y + local normalX, normalY = x / self._GWIDTH, y / self._GHEIGHT + + x = (x >= 0 and x <= self._WWIDTH * self._SCALE.x) and normalX * self._WWIDTH or nil + y = (y >= 0 and y <= self._WHEIGHT * self._SCALE.y) and normalY * self._WHEIGHT or nil + + return x, y +end + +--doesn't work - TODO +function push:toReal(x, y) + return x + self._OFFSET.x, y + self._OFFSET.y +end + +function push:switchFullscreen(winw, winh) + self._fullscreen = not self._fullscreen + local windowWidth, windowHeight = love.window.getDesktopDimensions() + + if self._fullscreen then --save windowed dimensions for later + self._WINWIDTH, self._WINHEIGHT = self._RWIDTH, self._RHEIGHT + elseif not self._WINWIDTH or not self._WINHEIGHT then + self._WINWIDTH, self._WINHEIGHT = windowWidth * .5, windowHeight * .5 + end + + self._RWIDTH = self._fullscreen and windowWidth or winw or self._WINWIDTH + self._RHEIGHT = self._fullscreen and windowHeight or winh or self._WINHEIGHT + + self:initValues() + + love.window.setFullscreen(self._fullscreen, "desktop") + if not self._fullscreen and (winw or winh) then + windowUpdateMode(self._RWIDTH, self._RHEIGHT) --set window dimensions + end +end + +function push:resize(w, h) + if self._highdpi then w, h = w / self._PSCALE, h / self._PSCALE end + self._RWIDTH = w + self._RHEIGHT = h + self:initValues() +end + +function push:getWidth() return self._WWIDTH end +function push:getHeight() return self._WHEIGHT end +function push:getDimensions() return self._WWIDTH, self._WHEIGHT end + +return push \ No newline at end of file diff --git a/src/ser.lua b/src/ser.lua new file mode 100644 index 0000000..0c6cc7b --- /dev/null +++ b/src/ser.lua @@ -0,0 +1,121 @@ +local pairs, ipairs, tostring, type, concat, dump, floor, format = pairs, ipairs, tostring, type, table.concat, string.dump, math.floor, string.format + +local function getchr(c) + return "\\" .. c:byte() +end + +local function make_safe(text) + return ("%q"):format(text):gsub('\n', 'n'):gsub("[\128-\255]", getchr) +end + +local oddvals = {[tostring(1/0)] = '1/0', [tostring(-1/0)] = '-1/0', [tostring(-(0/0))] = '-(0/0)', [tostring(0/0)] = '0/0'} +local function write(t, memo, rev_memo) + local ty = type(t) + if ty == 'number' then + t = format("%.17g", t) + return oddvals[t] or t + elseif ty == 'boolean' or ty == 'nil' then + return tostring(t) + elseif ty == 'string' then + return make_safe(t) + elseif ty == 'table' or ty == 'function' then + if not memo[t] then + local index = #rev_memo + 1 + memo[t] = index + rev_memo[index] = t + end + return '_[' .. memo[t] .. ']' + else + error("Trying to serialize unsupported type " .. ty) + end +end + +local kw = {['and'] = true, ['break'] = true, ['do'] = true, ['else'] = true, + ['elseif'] = true, ['end'] = true, ['false'] = true, ['for'] = true, + ['function'] = true, ['goto'] = true, ['if'] = true, ['in'] = true, + ['local'] = true, ['nil'] = true, ['not'] = true, ['or'] = true, + ['repeat'] = true, ['return'] = true, ['then'] = true, ['true'] = true, + ['until'] = true, ['while'] = true} +local function write_key_value_pair(k, v, memo, rev_memo, name) + if type(k) == 'string' and k:match '^[_%a][_%w]*$' and not kw[k] then + return (name and name .. '.' or '') .. k ..'=' .. write(v, memo, rev_memo) + else + return (name or '') .. '[' .. write(k, memo, rev_memo) .. ']=' .. write(v, memo, rev_memo) + end +end + +-- fun fact: this function is not perfect +-- it has a few false positives sometimes +-- but no false negatives, so that's good +local function is_cyclic(memo, sub, super) + local m = memo[sub] + local p = memo[super] + return m and p and m < p +end + +local function write_table_ex(t, memo, rev_memo, srefs, name) + if type(t) == 'function' then + return '_[' .. name .. ']=loadstring' .. make_safe(dump(t)) + end + local m = {} + local mi = 1 + for i = 1, #t do -- don't use ipairs here, we need the gaps + local v = t[i] + if v == t or is_cyclic(memo, v, t) then + srefs[#srefs + 1] = {name, i, v} + m[mi] = 'nil' + mi = mi + 1 + else + m[mi] = write(v, memo, rev_memo) + mi = mi + 1 + end + end + for k,v in pairs(t) do + if type(k) ~= 'number' or floor(k) ~= k or k < 1 or k > #t then + if v == t or k == t or is_cyclic(memo, v, t) or is_cyclic(memo, k, t) then + srefs[#srefs + 1] = {name, k, v} + else + m[mi] = write_key_value_pair(k, v, memo, rev_memo) + mi = mi + 1 + end + end + end + return '_[' .. name .. ']={' .. concat(m, ',') .. '}' +end + +return function(t) + local memo = {[t] = 0} + local rev_memo = {[0] = t} + local srefs = {} + local result = {} + + -- phase 1: recursively descend the table structure + local n = 0 + while rev_memo[n] do + result[n + 1] = write_table_ex(rev_memo[n], memo, rev_memo, srefs, n) + n = n + 1 + end + + -- phase 2: reverse order + for i = 1, n*.5 do + local j = n - i + 1 + result[i], result[j] = result[j], result[i] + end + + -- phase 3: add all the tricky cyclic stuff + for i, v in ipairs(srefs) do + n = n + 1 + result[n] = write_key_value_pair(v[2], v[3], memo, rev_memo, '_[' .. v[1] .. ']') + end + + -- phase 4: add something about returning the main table + if result[n]:sub(1, 5) == '_[0]=' then + result[n] = 'return ' .. result[n]:sub(6) + else + result[n + 1] = 'return _[0]' + end + + -- phase 5: just concatenate everything + result = concat(result, '\n') + return n > 1 and 'local _={}\n' .. result or result +end diff --git a/src/simpleScale.lua b/src/simpleScale.lua new file mode 100644 index 0000000..c417843 --- /dev/null +++ b/src/simpleScale.lua @@ -0,0 +1,123 @@ +simpleScale = {} +--Your Game's Aspect Ratio +local gAspectRatio +--The Window's Aspect Ratio +local wAspectRatio +--The scale between the game and the window's aspect ratio +simpleScale.scale = 1 + +local xt, yt = 0, 0, 1 +local gameW, gameH, windowW, windowH = 800, 600, 800, 600 + +-- Declares your game's width and height, and sets the window size/settings +-- To be used instead of love.window.setMode +-- [gw] and [gh] are the width and height of the initial game +-- [sw] and [sh] (optional) are the width and height of the final window +-- [settings] (optional) are settings for love.window.setMode +function simpleScale.setWindow(gw, gh, sw, sh, settings) + sw = sw or gw + sh = sh or gh + gAspectRatio = gw/gh + gameW = gw + gameH = gh + simpleScale.updateWindow(sw, sh, settings) +end + +-- Updates the Window size/settings +-- To be used instead of love.window.setMode +-- [sw] and [sh] are the width and height of the new Window +-- [settings] (optional) are settings for love.window.setMode +function simpleScale.updateWindow(sw, sh, settings) + love.window.setMode(sw, sh, settings) + windowW, windowH = love.graphics.getWidth(), love.graphics.getHeight() + wAspectRatio = windowW/windowH + + --Window aspect ratio is TALLER than game + if gAspectRatio > wAspectRatio then + scale = windowW/gameW + xt = 0 + yt = windowH/2 - (scale*gameH)/2 + + --Window aspect ratio is WIDER than game + elseif gAspectRatio < wAspectRatio then + scale = windowH/gameH + xt = windowW/2 - (scale*gameW)/2 + yt = 0 + + --Window and game aspect ratios are EQUAL + else + scale = windowW/gameW + + xt = 0 + yt = 0 + end + simpleScale.scale = scale +end + +-- If you screen is resizable on drag, you'll need to call this to make sure +-- the appropriate screen values stay updated +-- You can call it on love.update() with no trouble +function simpleScale.resizeUpdate() + windowW, windowH = love.graphics.getWidth(), love.graphics.getHeight() + wAspectRatio = windowW/windowH + + --Window aspect ratio is TALLER than game + if gAspectRatio > wAspectRatio then + scale = windowW/gameW + xt = 0 + yt = windowH/2 - (scale*gameH)/2 + + --Window aspect ratio is WIDER than game + elseif gAspectRatio < wAspectRatio then + scale = windowH/gameH + xt = windowW/2 - (scale*gameW)/2 + yt = 0 + + --Window and game aspect ratios are EQUAL + else + scale = windowW/gameW + + xt = 0 + yt = 0 + end + simpleScale.scale = scale +end + +-- Transforms the game's window relative to the entire window +-- Call this at the beginning of love.draw() +function simpleScale.set() + love.graphics.push() + love.graphics.translate(xt, yt) + love.graphics.scale(scale, scale) +end + +-- Untransforms the game's window +-- Call this at the end of love.draw +-- You can optionally make the letterboxes a specific color by passing +-- [color] (optional) a table of color values +function simpleScale.unSet(color) + love.graphics.scale(1/scale, 1/scale) + love.graphics.translate(-xt, -yt) + love.graphics.pop() + + --Draw the Letterboxes + local r,g,b,a = love.graphics.getColor() + local originalColor = love.graphics.getColor() + local boxColor + if color == nil then + boxColor = {0,0,0} + else + boxColor = color + end + love.graphics.setColor(boxColor) + --Horizontal bars + if gAspectRatio > wAspectRatio then + love.graphics.rectangle("fill", 0, 0, windowW, math.abs((gameH*scale - (windowH))/2)) + love.graphics.rectangle("fill", 0, windowH, windowW, -math.abs((gameH*scale - (windowH))/2)) + --Vertical bars + elseif gAspectRatio < wAspectRatio then + love.graphics.rectangle("fill", 0, 0, math.abs((gameW*scale - (windowW))/2),windowH) + love.graphics.rectangle("fill", windowW, 0, -math.abs((gameW*scale - (windowW))/2),windowH) + end + love.graphics.setColor(r,g,b,a) +end \ No newline at end of file diff --git a/src/tick.lua b/src/tick.lua new file mode 100644 index 0000000..5d00c7a --- /dev/null +++ b/src/tick.lua @@ -0,0 +1,70 @@ +-- tick +-- https://github.com/bjornbytes/tick +-- MIT License + +local tick = { + framerate = nil, + rate = .03, + timescale = 1, + sleep = .001, + dt = 0, + accum = 0, + tick = 1, + frame = 1 + } + + local timer = love.timer + local graphics = love.graphics + + love.run = function() + if not timer then + error('love.timer is required for tick') + end + + if love.load then love.load(love.arg.parseGameArguments(arg), arg) end + timer.step() + local lastframe = 0 + + love.update(0) + + return function() + tick.dt = timer.step() * tick.timescale + tick.accum = tick.accum + tick.dt + while tick.accum >= tick.rate do + tick.accum = tick.accum - tick.rate + + if love.event then + love.event.pump() + for name, a, b, c, d, e, f in love.event.poll() do + if name == 'quit' then + if not love.quit or not love.quit() then + return a or 0 + end + end + + love.handlers[name](a, b, c, d, e, f) + end + end + + tick.tick = tick.tick + 1 + if love.update then love.update(tick.rate) end + end + + while tick.framerate and timer.getTime() - lastframe < 1 / tick.framerate do + timer.sleep(.0005) + end + + lastframe = timer.getTime() + if graphics and graphics.isActive() then + graphics.origin() + graphics.clear(graphics.getBackgroundColor()) + tick.frame = tick.frame + 1 + if love.draw then love.draw() end + graphics.present() + end + + timer.sleep(tick.sleep) + end + end + + return tick \ No newline at end of file diff --git a/stateMachine.lua b/stateMachine.lua new file mode 100644 index 0000000..1063be4 --- /dev/null +++ b/stateMachine.lua @@ -0,0 +1,11 @@ +state = require("levels/"..gameState) +print("levels/"..gameState) +function stateUpdate(dt) + state = require("levels/"..gameState) + state.update(dt) +end + + +function stateDraw() + state.draw() +end \ No newline at end of file