commit 87e4b0cc4b5cab48a90b1db3fccf6b4ccebea883
Author: Madiwka3 <madi.turgunov.03@gmail.com>
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