├── .gitattributes ├── .gitignore ├── Ideas.txt ├── README.md ├── antivirus.lua ├── audio ├── bgm-start.ogg ├── bgm.ogg ├── bit.ogg ├── bit2.ogg ├── bit3.ogg ├── blip.ogg ├── explosion.ogg ├── gameover.ogg ├── hitproxy.ogg ├── jump.ogg ├── playerspawn.ogg └── title.ogg ├── bitenemy.lua ├── classes ├── console.lua ├── pausemenu.lua ├── player.lua ├── tile.lua └── trailmesh.lua ├── conf.lua ├── console.lua ├── firewall.lua ├── graphics ├── 1.png ├── 2.png ├── antivirus.png ├── bullet.png ├── crosshair.png ├── explosion.png ├── firewall.png ├── gameover.png ├── icon.png ├── links.txt ├── player - Copy.png ├── player.png ├── player_sheet.png ├── player_wireframe.png ├── proxy.png ├── proxy_intro.png ├── tile.png ├── tiles.png ├── warning.png └── windows_command_prompt.ttf ├── hack.lua ├── libraries ├── event.lua ├── middleclass.lua └── physics.lua ├── lisence.txt ├── main.lua ├── maps └── 1.png ├── mobile ├── andralog.lua ├── mobile.lua └── virtualbutton.lua ├── physics.lua ├── player.lua ├── proxy.lua ├── states ├── game.lua ├── title.lua └── win.lua ├── tile.lua └── win.lua /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /Ideas.txt: -------------------------------------------------------------------------------- 1 | Ideas 2 | • Scan lines shader? 3 | • Dash with left shift 4 | • After clearing a room, a random direction opens (left, right, or down) 5 | • More enemy types 6 | • Mini boss midway through the game (see top of main.lua for mid bosses) 7 | • 14 rooms 8 | • To destroy enemies use left mouse to shoot 9 | 10 | • Have Polybius sprite his OC for the player sprite 11 | • 4 directional angles 12 | • Needed animations: | idle | walk | run | jump | fall | wall cling | duck | 13 | • angles: 0, pi/4, pi/2, 7pi/4 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hax0r 2 | A Ludum Dare #33 Game 3 | 4 | # License 5 | I honestly don't mind if you make a mod of the game in some way, as long as credit is given. 6 | The game is non-commercial share alike 4.0. See: 7 | http://creativecommons.org/licenses/by-nc-sa/4.0/ for details 8 | -------------------------------------------------------------------------------- /antivirus.lua: -------------------------------------------------------------------------------- 1 | function newAntivirus(x, y) 2 | local av = {} 3 | 4 | av.x = x 5 | av.y = y 6 | 7 | av.ang = math.atan( (y - objects["player"][1].y) / (x - objects["player"][1].x) ) 8 | 9 | local speed = 120 10 | if x > objects["player"][1].x then 11 | speed = -120 12 | end 13 | 14 | av.speedx = math.cos(av.ang) * speed 15 | av.speedy = math.sin(av.ang) * speed 16 | 17 | av.width = 9 18 | av.height = 9 19 | 20 | av.active = true 21 | av.gravity = 0 22 | 23 | av.mask = { ["tile"] = true , ["player"] = true } 24 | av.quadi = 1 25 | av.timer = 0 26 | 27 | function av:update(dt) 28 | self.timer = self.timer + 8 * dt 29 | self.quadi = math.floor(self.timer%#antivirusquads)+1 30 | end 31 | 32 | function av:leftCollide(name, data) 33 | if name == "player" or name == "tile" then 34 | self:die() 35 | end 36 | end 37 | 38 | function av:rightCollide(name, data) 39 | if name == "player" or name == "tile" then 40 | self:die() 41 | end 42 | end 43 | 44 | function av:upCollide(name, data) 45 | if name == "player" or name == "tile" then 46 | self:die() 47 | end 48 | end 49 | 50 | function av:downCollide(name, data) 51 | if name == "player" or name == "tile" then 52 | self:die() 53 | end 54 | end 55 | 56 | function av:die() 57 | table.insert(objects["explosion"], newExplosion(self.x, self.y)) 58 | self.remove = true 59 | end 60 | 61 | function av:draw() 62 | love.graphics.draw(antivirusrocket, antivirusquads[self.quadi], self.x * scale, self.y * scale, 0, scale, scale) 63 | end 64 | 65 | return av 66 | end 67 | 68 | function newExplosion(x, y) 69 | local explosion = {} 70 | 71 | explosion.x = x 72 | explosion.y = y 73 | explosion.width = 9 74 | explosion.height = 9 75 | 76 | explosionsnd:play() 77 | 78 | explosion.graphic = love.graphics.newImage("graphics/explosion.png") 79 | explosion.quads = {} 80 | for k = 1, 16 do 81 | explosion.quads[k] = love.graphics.newQuad(( k - 1) * 10, 0, 9, 9, explosion.graphic:getWidth(), explosion.graphic:getHeight()) 82 | end 83 | 84 | explosion.timer = 0 85 | explosion.quadi = 1 86 | 87 | function explosion:update(dt) 88 | if self.quadi < #self.quads then 89 | self.timer = self.timer + 12 * dt 90 | self.quadi = math.floor(self.timer%#self.quads)+1 91 | 92 | tremorX = love.math.random(-10, 10) 93 | tremorY = love.math.random(-10, 10) 94 | else 95 | self.remove = true 96 | end 97 | end 98 | 99 | function explosion:draw() 100 | love.graphics.draw(self.graphic, self.quads[self.quadi], self.x * scale, self.y * scale, 0, scale, scale) 101 | end 102 | 103 | return explosion 104 | end -------------------------------------------------------------------------------- /audio/bgm-start.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/bgm-start.ogg -------------------------------------------------------------------------------- /audio/bgm.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/bgm.ogg -------------------------------------------------------------------------------- /audio/bit.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/bit.ogg -------------------------------------------------------------------------------- /audio/bit2.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/bit2.ogg -------------------------------------------------------------------------------- /audio/bit3.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/bit3.ogg -------------------------------------------------------------------------------- /audio/blip.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/blip.ogg -------------------------------------------------------------------------------- /audio/explosion.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/explosion.ogg -------------------------------------------------------------------------------- /audio/gameover.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/gameover.ogg -------------------------------------------------------------------------------- /audio/hitproxy.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/hitproxy.ogg -------------------------------------------------------------------------------- /audio/jump.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/jump.ogg -------------------------------------------------------------------------------- /audio/playerspawn.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/playerspawn.ogg -------------------------------------------------------------------------------- /audio/title.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/audio/title.ogg -------------------------------------------------------------------------------- /bitenemy.lua: -------------------------------------------------------------------------------- 1 | function newBit(x, y) 2 | local bit = {} 3 | 4 | bit.x = love.math.random(x - 10, x + 20) 5 | bit.y = y - 4 6 | bit.width = 4 7 | bit.height = 4 8 | 9 | local spd = {-60, 60} 10 | 11 | bit.speedx = 60 12 | bit.speedy = 0 13 | bit.gravity = 100 14 | 15 | bit.aiTimer = 0 16 | bit.aiTimerMax = love.math.random(0.1, 0.3) 17 | bit.speed = bit.speedx 18 | 19 | bit.mask = 20 | { 21 | ["tile"] = true, 22 | ["player"] = true 23 | } 24 | 25 | bit.turnAround = {false, false} 26 | 27 | bit.active = true 28 | 29 | function bit:update(dt) 30 | if self.aiTimer < self.aiTimerMax then 31 | self.aiTimer = self.aiTimer + dt 32 | else 33 | local doSomething = {"jump", "changespeed"} 34 | 35 | local aiThing = doSomething[love.math.random(#doSomething)] 36 | 37 | if aiThing == "jump" then 38 | if not self.jumping then 39 | self.speedy = -50 40 | self.jumping = true 41 | end 42 | end 43 | 44 | self.aiTimer = 0 45 | self.aiTimerMax = love.math.random(1, 2) 46 | end 47 | 48 | if self.turnAround[1] or self.turnAround[2] then 49 | if self.turnAround[1] then 50 | self.speedx = -self.speed 51 | self.turnAround[1] = false 52 | else 53 | self.speedx = self.speed 54 | self.turnAround[2] = false 55 | end 56 | end 57 | 58 | if self.y > gameFunctions.getHeight() then 59 | self:die() 60 | end 61 | end 62 | 63 | function bit:leftCollide(name, data) 64 | if name == "tile" then 65 | self.turnAround[2] = true 66 | end 67 | 68 | if name == "player" then 69 | return false 70 | end 71 | end 72 | 73 | function bit:rightCollide(name, data) 74 | if name == "tile" then 75 | self.turnAround[1] = true 76 | end 77 | 78 | if name == "player" then 79 | return false 80 | end 81 | end 82 | 83 | function bit:downCollide(name, data) 84 | self.jumping = false 85 | 86 | if name == "player" then 87 | return false 88 | end 89 | end 90 | 91 | function bit:upCollide(name, data) 92 | if name == "player" then 93 | return false 94 | end 95 | end 96 | 97 | function bit:draw() 98 | love.graphics.setColor(255, 255, 255) 99 | love.graphics.rectangle("fill", self.x * scale, self.y * scale, self.width * scale, self.height * scale) 100 | end 101 | 102 | function bit:die(ply) 103 | table.insert(objects["bitblood"], newBitBlood(self.x + self.width / 2 - 1, self.y + self.height / 2 - 1)) 104 | 105 | local low, high = 2, 8 106 | if events["udpopen"][3] then 107 | low, high = 16, 32 108 | end 109 | 110 | local s = love.math.random(low, high) 111 | 112 | local newAdd = s 113 | if combo > 1 then 114 | newAdd = s * combo 115 | end 116 | 117 | if scoreTypes[scorei] == "KB" then 118 | score = math.min(score + newAdd, 1024) 119 | else 120 | score = math.min(score, 1) 121 | end 122 | 123 | self.remove = true 124 | end 125 | 126 | return bit 127 | end 128 | 129 | function newBitBlood(x, y) 130 | local bitblood = {} 131 | 132 | bitblood.x = x 133 | bitblood.y = y 134 | bitblood.width = 2 135 | bitblood.height = 2 136 | bitblood.active = true 137 | bitblood.gravity = 20 138 | 139 | bitblood.speedx = 0 140 | bitblood.speedy = 0 141 | 142 | bit.passive = true 143 | bitblood.mask = {} 144 | 145 | bitsnd[love.math.random(#bitsnd)]:play() 146 | 147 | local filetypes = {".png", ".zip", ".dll", ".doc", ".txt", ".gif", ".flac", ".exe", ".sys"} 148 | 149 | local s = {} 150 | for k = 1, 4 do 151 | s[k] = {x = x, y = y, max = false} 152 | end 153 | 154 | bitblood.t = filetypes[love.math.random(#filetypes)] 155 | bitblood.fade = 1 156 | 157 | function bitblood:update(dt) 158 | for k = 1, #s do 159 | if s[k].y > self.y - 20 then 160 | if not s[k].max then 161 | s[k].y = s[k].y - 30 * dt 162 | end 163 | else 164 | s[k].max = true 165 | s[k].y = s[k].y + 30 * dt 166 | 167 | if s[k].y > gameFunctions.getHeight() then 168 | self.remove = true 169 | end 170 | end 171 | 172 | if k < 2 then 173 | s[k].x = s[k].x - 10 * dt 174 | else 175 | s[k].x = s[k].x + 10 * dt 176 | end 177 | end 178 | 179 | self.fade = math.max(0, self.fade - dt) 180 | end 181 | 182 | function bitblood:draw() 183 | for k = 1, #s do 184 | love.graphics.setColor(255, 255, 255) 185 | love.graphics.rectangle("fill", s[k].x * scale, s[k].y * scale, 2 * scale, 2 * scale) 186 | end 187 | 188 | love.graphics.setFont(consoleFont) 189 | love.graphics.setColor(255, 255, 255, 255 * self.fade) 190 | love.graphics.print(self.t, (self.x + self.width / 2) * scale - consoleFont:getWidth(self.t) / 2, (self.y + self.height / 2) * scale - consoleFont:getHeight(self.t) / 2) 191 | end 192 | 193 | function bitblood:die() 194 | -- body 195 | end 196 | 197 | return bitblood 198 | end -------------------------------------------------------------------------------- /classes/console.lua: -------------------------------------------------------------------------------- 1 | console = class("console") 2 | 3 | function console:init(string, color, func) 4 | self.x = 2 5 | self.y = 2 6 | self.width = gameFunctions.getWidth() - 4 7 | self.height = 16 8 | 9 | self.delay = 0.04 10 | self.i = 0 11 | self.timer = 0 12 | self.index = 1 13 | self.string = (string or "") 14 | self.fade = 1 15 | self.drawstring = "" 16 | 17 | self.endTimer = 0 18 | self.stringColor = color or {255, 255, 255} 19 | 20 | if func then 21 | func() 22 | end 23 | end 24 | 25 | 26 | function console:update(dt) 27 | if self.i < #self.string then 28 | if self.timer < self.delay then 29 | self.timer = self.timer + dt 30 | else 31 | hitproxysnd:play() 32 | 33 | local s = self.string 34 | self.i = self.i + 1 35 | self.drawstring = self.drawstring .. s:sub(self.i, self.i) 36 | 37 | self.timer = 0 38 | end 39 | else 40 | self.endTimer = self.endTimer + 2 * dt 41 | self.fade = math.floor(self.endTimer%2) 42 | 43 | if self.endTimer > 4 then 44 | self.remove = true 45 | end 46 | end 47 | end 48 | 49 | function console:draw() 50 | love.graphics.setFont(consoleFont) 51 | 52 | love.graphics.setColor(0, 0, 0, 200) 53 | love.graphics.rectangle("fill", self.x * scale, self.y * scale, self.width * scale, self.height * scale) 54 | love.graphics.setColor(self.stringColor) 55 | 56 | love.graphics.print("> " .. self.drawstring, (self.x + 2) * scale, (self.y + self.height / 2) * scale - consoleFont:getHeight(self.drawstring) / 2) 57 | 58 | if self.i == #self.string then 59 | love.graphics.setColor(self.stringColor[1], self.stringColor[2], self.stringColor[3], 255 * self.fade) 60 | love.graphics.print("_", (self.x + 2) * scale + consoleFont:getWidth("> " .. self.string), (self.y + self.height / 2) * scale - consoleFont:getHeight(self.string) / 2) 61 | end 62 | 63 | love.graphics.setFont(backgroundFont) 64 | end -------------------------------------------------------------------------------- /classes/pausemenu.lua: -------------------------------------------------------------------------------- 1 | function newPauseMenu() 2 | local menu = {} 3 | 4 | menu.x = (gameFunctions.getWidth() / 2 - 55) 5 | menu.y = (gameFunctions.getHeight() / 2 - 30) 6 | menu.width = 110 7 | menu.height = 60 8 | 9 | menu.items = 10 | { 11 | "Return to game", 12 | "Quit to menu", 13 | "Quit to desktop" 14 | } 15 | 16 | menu.itemi = 1 17 | 18 | function menu:draw() 19 | love.graphics.setColor(64, 64, 64) 20 | love.graphics.rectangle("fill", self.x * scale, self.y * scale, self.width * scale, self.height * scale) 21 | 22 | love.graphics.setColor(128, 128, 128) 23 | love.graphics.rectangle("line", self.x * scale, self.y * scale, self.width * scale, self.height * scale) 24 | 25 | love.graphics.setColor(255, 255, 255) 26 | 27 | love.graphics.setFont(pauseFont) 28 | love.graphics.print("Game Paused", (self.x + self.width / 2) * scale - pauseFont:getWidth("Game Paused") / 2, (self.y + 2) * scale) 29 | 30 | for k = 1, #self.items do 31 | love.graphics.print(self.items[k], (self.x + self.width / 2) * scale - pauseFont:getWidth(self.items[k]) / 2, ((self.y + 20) + (k - 1) * 14) * scale) 32 | end 33 | 34 | love.graphics.print("> ", (self.x + self.width / 2) * scale - pauseFont:getWidth(self.items[self.itemi]) / 2 - pauseFont:getWidth("> "), ((self.y + 20) + (self.itemi - 1) * 14) * scale) 35 | love.graphics.print(" <", (self.x + self.width / 2) * scale + pauseFont:getWidth(self.items[self.itemi]) / 2, ((self.y + 20) + (self.itemi - 1) * 14) * scale) 36 | end 37 | 38 | function menu:keypressed(key) 39 | if key == controls["down"] then 40 | self.itemi = math.min(self.itemi + 1, #self.items) 41 | end 42 | 43 | if key == controls["up"] then 44 | self.itemi = math.max(self.itemi - 1, 1) 45 | end 46 | 47 | if key == controls["jump"] then 48 | if self.itemi == 1 then 49 | paused = false 50 | elseif self.itemi == 2 then 51 | gameFunctions.changeState("title") 52 | else 53 | love.event.quit() 54 | end 55 | end 56 | end 57 | 58 | return menu 59 | end -------------------------------------------------------------------------------- /classes/player.lua: -------------------------------------------------------------------------------- 1 | player = class("player") 2 | 3 | function player:init(x, y, fadein) 4 | self.x = x 5 | self.y = y 6 | self.width = 20 7 | self.height = 33 8 | 9 | self.pointingangle = 0 10 | 11 | self.rightkey = false 12 | self.upkey = false 13 | self.downkey = false 14 | self.leftkey = false 15 | 16 | self.speedx = 0 17 | self.speedy = 0 18 | self.active = true 19 | self.gravity = 400 20 | 21 | self.mask = 22 | { 23 | ["tile"] = true, 24 | ["bit"] = true, 25 | ["antivirus"] = true 26 | } 27 | 28 | playerspawnsnd:play() 29 | 30 | self.quads = {} 31 | 32 | for k = 1, 4 do 33 | self.quads[k] = love.graphics.newQuad((k - 1) * 13, 0, 12, 18, playerimg:getWidth(), playerimg:getHeight()) 34 | end 35 | 36 | self.quadi = 1 37 | self.timer = 0 38 | self.rate = 8 39 | 40 | self.fade = 1 41 | self.fadeOut = false 42 | self.jumping = false 43 | 44 | self.fadeOut = fadein or false 45 | 46 | if fadein then 47 | self.fade = 0 48 | end 49 | 50 | self.scale = scale 51 | self.offset = 0 52 | 53 | self.animations = 54 | { 55 | ["idle"] = {timer = 0, rate = 0.5, frames = {1, 2}}, 56 | ["walk"] = {timer = 0, rate = 4, frames = {3, 4, 5, 4}} 57 | } 58 | 59 | self.crosshair = love.graphics.newImage("graphics/crosshair.png") 60 | self.angle = 0 61 | 62 | self.animation = "idle" 63 | 64 | circleX, circleY = self.x, self.y 65 | end 66 | 67 | function player:update(dt) 68 | if not self.rightkey and not self.leftkey and not self.downkey and not self.upkey then 69 | self.speedx = 0 70 | elseif self.rightkey then 71 | self.speedx = 60 72 | elseif self.leftkey then 73 | self.speedx = -60 74 | end 75 | 76 | self.timer = self.timer + self.rate * dt 77 | self.quadi = math.floor(self.timer%4)+1 78 | 79 | if self.fade ~= 1 then 80 | self.fade = math.min(1, self.fade + dt) 81 | self.speedx = 0 82 | self.speedy = 0 83 | end 84 | 85 | if self.y > gameFunctions.getHeight() then 86 | self.y = 0 87 | mapscrolly = mapscrolly + (-12 * 16) * dt 88 | elseif self.y < 0 then 89 | self.y = gameFunctions.getHeight() 90 | mapscrolly = mapscrolly - (12 * 16) * dt 91 | end 92 | 93 | self.animations[self.animation].timer = self.animations[self.animation].timer + self.animations[self.animation].rate * dt 94 | self.quadi = self.animations[self.animation].frames[math.floor(self.timer%#self.animations[self.animation].frames)+1] 95 | 96 | self.angle = math.atan2((love.mouse.getY() - 2) - (self.y + self.height / 2) * scale, (love.mouse.getX() - 2) - (self.x + self.width / 2) * scale) 97 | if love.mouse.isDown("l") then 98 | objects["bullet"][1] = bullet:new(self.x + self.width / 2, self.y + self.height / 2, self.angle) 99 | end 100 | 101 | if self.trail then 102 | self.trail:update(dt) 103 | end 104 | end 105 | 106 | function player:draw() 107 | love.graphics.setColor(255, 255, 255, 255 * self.fade) 108 | love.graphics.draw(playerimg, self.x * scale, self.y * scale, 0, self.scale, scale, self.offset) 109 | 110 | love.graphics.draw(self.crosshair, love.mouse.getX() - 2, love.mouse.getY() - 2, 0, scale, scale) 111 | 112 | if self.trail then 113 | self.trail:draw() 114 | end 115 | end 116 | 117 | function player:moveright(move) 118 | self.rightkey = move 119 | 120 | if move then 121 | self.scale = scale 122 | self.offset = 0 123 | end 124 | end 125 | 126 | function player:moveleft(move) 127 | self.leftkey = move 128 | 129 | if move then 130 | self.scale = -scale 131 | self.offset = self.width 132 | end 133 | end 134 | 135 | function player:dash() 136 | self.trail = trailmesh:new(self.x * scale, self.y * scale, playerimg, self.width * scale, 0.3, 0.3) 137 | end 138 | 139 | function player:jump(shortHop) 140 | if not self.jumping and not shortHop then 141 | self.speedy = -160 142 | self.jumping = true 143 | 144 | if not paused then 145 | if self.fade == 1 then 146 | jumpsnd:play() 147 | end 148 | end 149 | else 150 | if shortHop then 151 | self.speedy = -120 152 | self.jumping = true 153 | end 154 | end 155 | end 156 | 157 | function player:downCollide(name, data) 158 | if name == "bit" or name == "proxy" then 159 | if self.speedy > 0 then 160 | self:jump(true) 161 | 162 | if name == "bit" then 163 | data:die() 164 | elseif name == "proxy" then 165 | data.gravity = 180 166 | hitproxysnd:play() 167 | end 168 | 169 | combo = combo + 1 170 | end 171 | return false 172 | end 173 | 174 | if name == "firewall" then 175 | if data.fade == 1 then 176 | self:die() 177 | else 178 | return false 179 | end 180 | end 181 | 182 | if name == "antivirus" then 183 | self:die() 184 | end 185 | 186 | self.jumping = false 187 | end 188 | 189 | function player:upCollide(name, data) 190 | if name == "bit" or name == "proxy" then 191 | return false 192 | end 193 | 194 | if name == "firewall" then 195 | if data.fade == 1 then 196 | self:die() 197 | else 198 | return false 199 | end 200 | end 201 | 202 | if name == "antivirus" then 203 | self:die() 204 | end 205 | end 206 | 207 | function player:leftCollide(name, data) 208 | if name == "bit" or name == "proxy" then 209 | return false 210 | end 211 | 212 | if name == "tile" then 213 | if self.speedx < 0 then 214 | self.speedy = -60 215 | end 216 | end 217 | 218 | if name == "firewall" then 219 | if data.fade == 1 then 220 | self:die() 221 | else 222 | return false 223 | end 224 | end 225 | 226 | if name == "antivirus" then 227 | self:die() 228 | end 229 | end 230 | 231 | function player:rightCollide(name, data) 232 | if name == "bit" or name == "proxy" then 233 | return false 234 | end 235 | 236 | if name == "tile" then 237 | if self.speedx > 0 then 238 | self.speedy = -60 239 | end 240 | end 241 | 242 | if name == "firewall" then 243 | if data.fade == 1 then 244 | self:die() 245 | else 246 | return false 247 | end 248 | end 249 | 250 | if name == "antivirus" then 251 | self:die() 252 | end 253 | end 254 | 255 | function player:die(win) 256 | table.insert(objects["digits"], death:new(self.x + self.width / 2 - 4, self.y - 3)) 257 | self.remove = true 258 | 259 | --obviously 260 | if not win then 261 | gameover = true 262 | end 263 | end 264 | 265 | death = class("death") 266 | 267 | function death:init(x, y) 268 | local deathn = {} 269 | local values = {"0", "1"} 270 | for k = 1, 6 do 271 | deathn[k] = { x = x , y = y + (k - 1) * 6 , value = values[love.math.random(#values)], speed = (math.random() * 2 - 1) * 40, timer = 0 } 272 | end 273 | 274 | self.x = x 275 | self.y = y 276 | self.width = 16 277 | self.height = 16 278 | 279 | gameoversnd:play() 280 | end 281 | 282 | function death:update(dt) 283 | for k = 1, #deathn do 284 | deathn[k].x = deathn[k].x + deathn[k].speed * dt 285 | 286 | if deathn[k].timer < 0.8 then 287 | deathn[k].timer = deathn[k].timer + dt 288 | deathn[k].y = deathn[k].y - 30 * dt 289 | else 290 | deathn[k].y = deathn[k].y + 30 * dt 291 | end 292 | end 293 | end 294 | 295 | function death:draw() 296 | love.graphics.setFont(consoleFont) 297 | for k = 1, #deathn do 298 | love.graphics.setColor(0, 150, 0) 299 | love.graphics.print(deathn[k].value, deathn[k].x * scale, deathn[k].y * scale) 300 | end 301 | end -------------------------------------------------------------------------------- /classes/tile.lua: -------------------------------------------------------------------------------- 1 | tile = class("tile") 2 | 3 | function tile:init(x, y, id, background) 4 | self.x = x 5 | self.y = y 6 | 7 | self.width = 16 8 | self.height = 16 9 | 10 | self.speedx = 0 11 | self.speedy = 0 12 | 13 | gameBatch:add(tilequads[id][love.math.random(4)], self.x * scale, self.y * scale, 0, scale, scale) 14 | 15 | self.passive = false 16 | 17 | if background then 18 | gameBatch:add(tilequads[id][love.math.random(5, 8)], self.x * scale, self.y * scale, 0, scale, scale) 19 | self.passive = true 20 | end 21 | end -------------------------------------------------------------------------------- /classes/trailmesh.lua: -------------------------------------------------------------------------------- 1 | trailmesh = class("trailmesh") 2 | 3 | function trailmesh:init(x, y, img, width, lifetime, interval, method) 4 | self.type = "trailmesh" 5 | 6 | self.x = x 7 | self.y = y 8 | self.img = img 9 | self.width = width 10 | self.lifetime = lifetime 11 | self.interval = interval 12 | self.method = method or "stretch" 13 | 14 | self:reset() 15 | 16 | self.mesh = love.graphics.newMesh(self.verts,self.img,"strip") 17 | end 18 | 19 | function trailmesh:update(dt) 20 | self.timer = self.timer + dt 21 | if self.timer > self.interval then 22 | if self.method == "repeat" then 23 | self.length = self.points[1][5] 24 | end 25 | table.insert(self.points, 1, {self.x,self.y,self.lifetime}) 26 | self.timer = self.timer - self.interval 27 | end 28 | 29 | self.points[1] = {self.x,self.y,self.lifetime,self.width} 30 | 31 | for point,v in pairs(self.points) do 32 | local pv = self.points[point+1] 33 | local nv = self.points[point-1] 34 | 35 | if v[3] < -self.interval*1.1 then 36 | table.remove(self.points, #self.points) 37 | table.remove(self.verts, #self.verts) 38 | table.remove(self.verts, #self.verts) 39 | break 40 | end 41 | 42 | local lifetime = v[3]/self.lifetime 43 | 44 | if self.method == "stretch" then 45 | if point == 1 then 46 | local dist = math.sqrt((v[1]-pv[1])^2+(v[2]-pv[2])^2) 47 | local vert = {(v[2]-pv[2])*v[4]/(dist*2), (v[1]-pv[1])*v[4]/(dist*2)} 48 | 49 | self.verts[1] = { 50 | v[1]+vert[1], 51 | v[2]-vert[2], 52 | lifetime, 53 | 0} 54 | self.verts[2] = { 55 | v[1]-vert[1], 56 | v[2]+vert[2], 57 | lifetime, 58 | 1} 59 | elseif point == #self.points then 60 | local dist = math.sqrt((nv[1]-v[1])^2+(nv[2]-v[2])^2) 61 | local vert = {(nv[2]-v[2])*v[4]/(dist*2), -(nv[1]-v[1])*v[4]/(dist*2)} 62 | 63 | self.verts[#self.points*2-1] = { 64 | v[1]+vert[1], 65 | v[2]-vert[2], 66 | lifetime, 67 | 0} 68 | self.verts[#self.points*2] = { 69 | v[1]-vert[1], 70 | v[2]+vert[2], 71 | lifetime, 72 | 1} 73 | else 74 | local dist = math.sqrt((nv[1]-pv[1])^2+(nv[2]-pv[2])^2) 75 | local vert = {(nv[2]-pv[2])*v[4]/(dist*2), (nv[1]-pv[1])*v[4]/(dist*2)} 76 | 77 | self.verts[point*2-1] = { 78 | v[1]+vert[1], 79 | v[2]-vert[2], 80 | lifetime, 81 | 0} 82 | self.verts[point*2] = { 83 | v[1]-vert[1], 84 | v[2]+vert[2], 85 | lifetime, 86 | 1} 87 | end 88 | elseif self.method == "repeat" then 89 | if point == 1 then 90 | local dist = math.sqrt((v[1]-pv[1])^2+(v[2]-pv[2])^2) 91 | local vert = {(v[2]-pv[2])*v[4]/(dist*2), (v[1]-pv[1])*v[4]/(dist*2)} 92 | 93 | v[5] = dist/(self.img:getWidth()/(self.img:getHeight()/self.width)) + self.length 94 | 95 | self.verts[1] = { 96 | v[1]+vert[1], 97 | v[2]-vert[2], 98 | v[5], 99 | 0, 100 | 255, 101 | 255, 102 | 255, 103 | 255*lifetime} 104 | self.verts[2] = { 105 | v[1]-vert[1], 106 | v[2]+vert[2], 107 | v[5], 108 | 1, 109 | 255, 110 | 255, 111 | 255, 112 | 255*lifetime} 113 | elseif point == #self.points then 114 | local dist = math.sqrt((nv[1]-v[1])^2+(nv[2]-v[2])^2) 115 | local vert = {(nv[2]-v[2])*v[4]/(dist*2), -(nv[1]-v[1])*v[4]/(dist*2)} 116 | 117 | self.verts[#self.points*2-1] = { 118 | v[1]+vert[1], 119 | v[2]-vert[2], 120 | v[5], 121 | 0, 122 | 255, 123 | 255, 124 | 255, 125 | 1} 126 | self.verts[#self.points*2] = { 127 | v[1]-vert[1], 128 | v[2]+vert[2], 129 | v[5], 130 | 1, 131 | 255, 132 | 255, 133 | 255, 134 | 1} 135 | else 136 | local dist = math.sqrt((nv[1]-pv[1])^2+(nv[2]-pv[2])^2) 137 | local vert = {(nv[2]-pv[2])*v[4]/(dist*2), (nv[1]-pv[1])*v[4]/(dist*2)} 138 | 139 | self.verts[point*2-1] = { 140 | v[1]+vert[1], 141 | v[2]-vert[2], 142 | v[5], 143 | 0, 144 | 255, 145 | 255, 146 | 255, 147 | 255*(lifetime+self.interval)} 148 | self.verts[point*2] = { 149 | v[1]-vert[1], 150 | v[2]+vert[2], 151 | v[5], 152 | 1, 153 | 255, 154 | 255, 155 | 255, 156 | 255*(lifetime+self.interval)} 157 | end 158 | end 159 | self.points[point][3] = v[3] - dt 160 | end 161 | if #self.verts > 3 then 162 | self.mesh:setVertices(self.verts) 163 | end 164 | end 165 | 166 | function trailmesh:draw() 167 | love.graphics.draw(self.mesh) 168 | end 169 | 170 | function trailmesh:setWidth(size, part) 171 | if part == "base" or not part then 172 | self.width = size 173 | elseif part == "all" then 174 | for k,v in pairs(self.points) do 175 | v[4] = size 176 | end 177 | end 178 | end 179 | 180 | function trailmesh:reset() 181 | self.timer = 0 182 | self.length = 0 183 | self.points = {{self.x,self.y,self.lifetime,self.width,0},{self.x,self.y,self.lifetime-self.interval,self.width,0}} 184 | self.verts = {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}} 185 | end -------------------------------------------------------------------------------- /conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf(t) 2 | t.console = false 3 | end -------------------------------------------------------------------------------- /console.lua: -------------------------------------------------------------------------------- 1 | function newConsole(string, color, func) 2 | local console = {} 3 | 4 | console.x = 2 5 | console.y = 2 6 | console.width = gameFunctions.getWidth() - 4 7 | console.height = 16 8 | 9 | console.delay = 0.04 10 | console.i = 0 11 | console.timer = 0 12 | console.index = 1 13 | console.string = "user@LudumDare33: " .. string or "user@LudumDare33: " 14 | console.fade = 1 15 | console.drawstring = "" 16 | 17 | console.endTimer = 0 18 | console.stringColor = color or {255, 255, 255} 19 | 20 | if func then 21 | func() 22 | end 23 | 24 | function console:update(dt) 25 | if self.i < #self.string then 26 | if self.timer < self.delay then 27 | self.timer = self.timer + dt 28 | else 29 | hitproxysnd:play() 30 | 31 | local s = self.string 32 | self.i = self.i + 1 33 | self.drawstring = self.drawstring .. s:sub(self.i, self.i) 34 | 35 | self.timer = 0 36 | end 37 | else 38 | self.endTimer = self.endTimer + 2 * dt 39 | self.fade = math.floor(self.endTimer%2) 40 | 41 | if self.endTimer > 4 then 42 | self.remove = true 43 | end 44 | end 45 | end 46 | 47 | function console:draw() 48 | love.graphics.setFont(consoleFont) 49 | 50 | love.graphics.setColor(0, 0, 0, 200) 51 | love.graphics.rectangle("fill", self.x * scale, self.y * scale, self.width * scale, self.height * scale) 52 | love.graphics.setColor(self.stringColor) 53 | 54 | love.graphics.print("> " .. self.drawstring, (self.x + 2) * scale, (self.y + self.height / 2) * scale - consoleFont:getHeight(self.drawstring) / 2) 55 | 56 | if self.i == #self.string then 57 | love.graphics.setColor(self.stringColor[1], self.stringColor[2], self.stringColor[3], 255 * self.fade) 58 | love.graphics.print("_", (self.x + 2) * scale + consoleFont:getWidth("> " .. self.string), (self.y + self.height / 2) * scale - consoleFont:getHeight(self.string) / 2) 59 | end 60 | 61 | love.graphics.setFont(backgroundFont) 62 | end 63 | 64 | return console 65 | end -------------------------------------------------------------------------------- /firewall.lua: -------------------------------------------------------------------------------- 1 | function newFirewall(x, y) 2 | local wall = {} 3 | 4 | wall.x = x 5 | wall.y = y 6 | wall.width = 16 7 | wall.height = 16 8 | 9 | wall.mask = {} 10 | 11 | wall.speedx = 0 12 | wall.speedy = 0 13 | 14 | wall.timer = 0 15 | wall.quadi = 1 16 | wall.animationtimer = 0 17 | wall.fade = 0 18 | 19 | function wall:upCollide(name, data) 20 | if name == "player" then 21 | return false 22 | end 23 | end 24 | 25 | function wall:downCollide(name, data) 26 | if name == "player" then 27 | return false 28 | end 29 | end 30 | 31 | function wall:leftCollide(name, data) 32 | if name == "player" then 33 | return false 34 | end 35 | end 36 | 37 | function wall:rightCollide(name, data) 38 | if name == "player" then 39 | return false 40 | end 41 | end 42 | 43 | function wall:update(dt) 44 | if self.timer < 6 then 45 | self.timer = self.timer + dt 46 | else 47 | self.remove = true 48 | end 49 | 50 | self.fade = math.min(self.fade + dt / 2, 1) 51 | 52 | self.animationtimer = self.animationtimer + 8 *dt 53 | self.quadi = math.floor(self.animationtimer%8)+1 54 | end 55 | 56 | function wall:draw() 57 | love.graphics.setColor(255, 255, 255, 255 * self.fade) 58 | love.graphics.draw(firewallimg, firewallquads[self.quadi], self.x * scale, self.y * scale, 0, scale, scale) 59 | end 60 | 61 | return wall 62 | end -------------------------------------------------------------------------------- /graphics/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/1.png -------------------------------------------------------------------------------- /graphics/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/2.png -------------------------------------------------------------------------------- /graphics/antivirus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/antivirus.png -------------------------------------------------------------------------------- /graphics/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/bullet.png -------------------------------------------------------------------------------- /graphics/crosshair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/crosshair.png -------------------------------------------------------------------------------- /graphics/explosion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/explosion.png -------------------------------------------------------------------------------- /graphics/firewall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/firewall.png -------------------------------------------------------------------------------- /graphics/gameover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/gameover.png -------------------------------------------------------------------------------- /graphics/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/icon.png -------------------------------------------------------------------------------- /graphics/links.txt: -------------------------------------------------------------------------------- 1 | http://www.dafont.com/windows-command-prompt.font -------------------------------------------------------------------------------- /graphics/player - Copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/player - Copy.png -------------------------------------------------------------------------------- /graphics/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/player.png -------------------------------------------------------------------------------- /graphics/player_sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/player_sheet.png -------------------------------------------------------------------------------- /graphics/player_wireframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/player_wireframe.png -------------------------------------------------------------------------------- /graphics/proxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/proxy.png -------------------------------------------------------------------------------- /graphics/proxy_intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/proxy_intro.png -------------------------------------------------------------------------------- /graphics/tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/tile.png -------------------------------------------------------------------------------- /graphics/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/tiles.png -------------------------------------------------------------------------------- /graphics/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/warning.png -------------------------------------------------------------------------------- /graphics/windows_command_prompt.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/graphics/windows_command_prompt.ttf -------------------------------------------------------------------------------- /hack.lua: -------------------------------------------------------------------------------- 1 | function newHack(x, y) 2 | local hack = {} 3 | 4 | hack.x = x 5 | hack.y = y 6 | hack.width = 20 7 | hack.height = 3 8 | 9 | hack.passive = true 10 | 11 | return hack 12 | end -------------------------------------------------------------------------------- /libraries/event.lua: -------------------------------------------------------------------------------- 1 | eventsystem = class("eventsystem") 2 | 3 | function eventsystem:init() 4 | self.sleep = 0 5 | self.i = 0 6 | self.events = {} 7 | end 8 | 9 | function eventsystem:update(dt) 10 | if self.i < #self.events then 11 | if self.sleep > 0 then 12 | self.sleep = math.max(0, self.sleep - dt) 13 | end 14 | 15 | if self.sleep == 0 then 16 | self.i = self.i + 1 17 | 18 | local v = self.events[self.i] 19 | 20 | if v.cmd == "console" then 21 | objects["console"][1] = console:new(v.args[1], v.args[2], v.args[3]) 22 | elseif v.cmd == "wait" then 23 | self.sleep = v.args 24 | elseif v.cmd == "spawnplayer" then 25 | objects["player"][1] = player:new(v.args[1], v.args[2], true) 26 | end 27 | end 28 | end 29 | end 30 | 31 | function eventsystem:queue(e, args) 32 | table.insert(self.events, {cmd = e, args = args}) 33 | end 34 | 35 | function eventsystem:clear() 36 | self.events = {} 37 | end -------------------------------------------------------------------------------- /libraries/middleclass.lua: -------------------------------------------------------------------------------- 1 | local middleclass = { 2 | _VERSION = 'middleclass v3.0.0', 3 | _DESCRIPTION = 'Object Orientation for Lua', 4 | _LICENSE = [[ 5 | MIT LICENSE 6 | 7 | Copyright (c) 2011 Enrique García Cota 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a 10 | copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included 18 | in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | ]] 28 | 29 | --Maurice here; I renamed initialize to init for my use. Just so you know. 30 | } 31 | 32 | local function _setClassDictionariesMetatables(aClass) 33 | local dict = aClass.__instanceDict 34 | dict.__index = dict 35 | 36 | local super = aClass.super 37 | if super then 38 | local superStatic = super.static 39 | setmetatable(dict, super.__instanceDict) 40 | setmetatable(aClass.static, { __index = function(_,k) return dict[k] or superStatic[k] end }) 41 | else 42 | setmetatable(aClass.static, { __index = function(_,k) return dict[k] end }) 43 | end 44 | end 45 | 46 | local function _setClassMetatable(aClass) 47 | setmetatable(aClass, { 48 | __tostring = function() return "class " .. aClass.name end, 49 | __index = aClass.static, 50 | __newindex = aClass.__instanceDict, 51 | __call = function(self, ...) return self:new(...) end 52 | }) 53 | end 54 | 55 | local function _createClass(name, super) 56 | local aClass = { name = name, super = super, static = {}, __mixins = {}, __instanceDict={} } 57 | aClass.subclasses = setmetatable({}, {__mode = "k"}) 58 | 59 | _setClassDictionariesMetatables(aClass) 60 | _setClassMetatable(aClass) 61 | 62 | return aClass 63 | end 64 | 65 | local function _createLookupMetamethod(aClass, name) 66 | return function(...) 67 | local method = aClass.super[name] 68 | assert( type(method)=='function', tostring(aClass) .. " doesn't implement metamethod '" .. name .. "'" ) 69 | return method(...) 70 | end 71 | end 72 | 73 | local function _setClassMetamethods(aClass) 74 | for _,m in ipairs(aClass.__metamethods) do 75 | aClass[m]= _createLookupMetamethod(aClass, m) 76 | end 77 | end 78 | 79 | local function _setDefaultInitializeMethod(aClass, super) 80 | aClass.init = function(instance, ...) 81 | return super.init(instance, ...) 82 | end 83 | end 84 | 85 | local function _includeMixin(aClass, mixin) 86 | assert(type(mixin)=='table', "mixin must be a table") 87 | for name,method in pairs(mixin) do 88 | if name ~= "included" and name ~= "static" then aClass[name] = method end 89 | end 90 | if mixin.static then 91 | for name,method in pairs(mixin.static) do 92 | aClass.static[name] = method 93 | end 94 | end 95 | if type(mixin.included)=="function" then mixin:included(aClass) end 96 | aClass.__mixins[mixin] = true 97 | end 98 | 99 | local Object = _createClass("Object", nil) 100 | 101 | Object.static.__metamethods = { '__add', '__call', '__concat', '__div', '__le', '__lt', 102 | '__mod', '__mul', '__pow', '__sub', '__tostring', '__unm' } 103 | 104 | function Object.static:allocate() 105 | assert(type(self) == 'table', "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'") 106 | return setmetatable({ class = self }, self.__instanceDict) 107 | end 108 | 109 | function Object.static:new(...) 110 | local instance = self:allocate() 111 | instance:init(...) 112 | return instance 113 | end 114 | 115 | function Object.static:subclass(name) 116 | assert(type(self) == 'table', "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'") 117 | assert(type(name) == "string", "You must provide a name(string) for your class") 118 | 119 | local subclass = _createClass(name, self) 120 | _setClassMetamethods(subclass) 121 | _setDefaultInitializeMethod(subclass, self) 122 | self.subclasses[subclass] = true 123 | self:subclassed(subclass) 124 | 125 | return subclass 126 | end 127 | 128 | function Object.static:subclassed(other) end 129 | 130 | function Object.static:isSubclassOf(other) 131 | return type(other) == 'table' and 132 | type(self) == 'table' and 133 | type(self.super) == 'table' and 134 | ( self.super == other or 135 | type(self.super.isSubclassOf) == 'function' and 136 | self.super:isSubclassOf(other) 137 | ) 138 | end 139 | 140 | function Object.static:include( ... ) 141 | assert(type(self) == 'table', "Make sure you that you are using 'Class:include' instead of 'Class.include'") 142 | for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end 143 | return self 144 | end 145 | 146 | function Object.static:includes(mixin) 147 | return type(mixin) == 'table' and 148 | type(self) == 'table' and 149 | type(self.__mixins) == 'table' and 150 | ( self.__mixins[mixin] or 151 | type(self.super) == 'table' and 152 | type(self.super.includes) == 'function' and 153 | self.super:includes(mixin) 154 | ) 155 | end 156 | 157 | function Object:init() end 158 | 159 | function Object:__tostring() return "instance of " .. tostring(self.class) end 160 | 161 | function Object:isInstanceOf(aClass) 162 | return type(self) == 'table' and 163 | type(self.class) == 'table' and 164 | type(aClass) == 'table' and 165 | ( aClass == self.class or 166 | type(aClass.isSubclassOf) == 'function' and 167 | self.class:isSubclassOf(aClass) 168 | ) 169 | end 170 | 171 | 172 | 173 | function middleclass.class(name, super, ...) 174 | super = super or Object 175 | return super:subclass(name, ...) 176 | end 177 | 178 | middleclass.Object = Object 179 | 180 | setmetatable(middleclass, { __call = function(_, ...) return middleclass.class(...) end }) 181 | 182 | return middleclass 183 | -------------------------------------------------------------------------------- /libraries/physics.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Turtle's Physics Library 3 | All code is mine. 4 | (c) 2015 Tiny Turtle Industries 5 | (Obviously same licensing as the game) 6 | --]] 7 | 8 | function physicsupdate(dt) 9 | local obj = objects 10 | 11 | for name, objectT in pairs(obj) do 12 | if name ~= "tile" then --not updating tiles! 13 | for _, objData in pairs(objectT) do --check object variables 14 | if objData.active and not objData.static then 15 | 16 | local hor, ver = false, false 17 | 18 | objData.speedy = math.min(objData.speedy + objData.gravity * dt, 10 * 16) --add gravity to objects 19 | 20 | for name2, object2T in pairs(obj) do 21 | if objData.mask[name2] == true and not objData.passive then 22 | hor, ver = checkCollision(objectT, object2T, objData, name, name2, dt) 23 | else 24 | checkPassive(objectT, object2T, objData, name, name2, dt) 25 | end 26 | end 27 | 28 | if not hor then 29 | objData.x = objData.x + objData.speedx * dt 30 | end 31 | 32 | if not ver then 33 | objData.y = objData.y + objData.speedy * dt 34 | end 35 | end 36 | end 37 | end 38 | end 39 | end 40 | 41 | function checkRectangle(x, y, w, h, obj) 42 | 43 | if type(obj) == "string" then 44 | for k, v in pairs(objects[obj]) do 45 | if aabb(x, y, w, h, v.x, v.y, v.width, v.height) then 46 | return true 47 | end 48 | end 49 | return false 50 | else 51 | for k = 1, #obj do 52 | local v = obj[k] 53 | for j, v in pairs(objects[v]) do 54 | if aabb(x, y, w, h, v.x, v.y, v.width, v.height) then 55 | return true 56 | end 57 | end 58 | end 59 | return false 60 | end 61 | 62 | end 63 | 64 | function checkPassive(objTable, obj2Table, objData, objName, obj2Name, dt) 65 | for _, obj2Data in pairs(obj2Table) do 66 | if aabb(objData.x, objData.y + objData.speedy * dt, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) or aabb(objData.x + objData.speedx * dt, objData.y, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then --was vertical 67 | if objData.passiveCollide then 68 | objData:passiveCollide(obj2Name, obj2Data) 69 | end 70 | end 71 | end 72 | end 73 | 74 | function checkCollision(objTable, obj2Table, objData, objName, obj2Name, dt) 75 | local hor, ver = false, false 76 | 77 | for _, obj2Data in pairs(obj2Table) do 78 | if not obj2Data.passive then 79 | 80 | if aabb(objData.x + objData.speedx * dt, objData.y + objData.speedy * dt, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then 81 | 82 | if aabb(objData.x, objData.y + objData.speedy * dt, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then --was vertical 83 | ver = verticalCollide(objName, objData, obj2Name, obj2Data) 84 | elseif aabb(objData.x + objData.speedx * dt, objData.y, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then 85 | hor = horizontalCollide(objName, objData, obj2Name, obj2Data) 86 | else 87 | --dat bug doe 88 | --[[if (objData.speedy - objData.gravity * dt) < (objData.speedx) then 89 | ver = verticalCollide(objName, objData, obj2Name, obj2Data) 90 | else 91 | hor = horizontalCollide(objName, objData, obj2Name, obj2Data) 92 | end]] 93 | end 94 | 95 | end 96 | 97 | else 98 | checkPassive(objTable, obj2Table, objData, objName, obj2Name, dt) 99 | hor = false 100 | ver = false 101 | end 102 | end 103 | 104 | return hor, ver 105 | end 106 | 107 | function horizontalCollide(objName, objData, obj2Name, obj2Data) 108 | local changedspeed = true 109 | 110 | if objData.speedx > 0 then 111 | if objData.rightCollide then --first object collision 112 | changedspeed = objData:rightCollide(obj2Name, obj2Data) 113 | if changedspeed ~= false then 114 | objData.x = obj2Data.x - objData.width 115 | objData.speedx = 0 116 | end 117 | else 118 | objData.x = obj2Data.x - objData.width 119 | objData.speedx = 0 120 | changedspeed = true 121 | end 122 | 123 | if obj2Data.leftCollide then --opposing object collides 124 | changedspeed = obj2Data:leftCollide(objName, objData) --Item 2 collides.. 125 | if changedspeed ~= false then 126 | if obj2Data.speedx < 0 then 127 | obj2Data.speedx = 0 128 | end 129 | end 130 | else 131 | if obj2Data.speedx < 0 then 132 | obj2Data.speedx = 0 133 | end 134 | end 135 | else 136 | if objData.leftCollide then 137 | changedspeed = objData:leftCollide(obj2Name, obj2Data) 138 | if changedspeed ~= false then 139 | objData.x = obj2Data.x + obj2Data.width 140 | objData.speedx = 0 141 | end 142 | else 143 | objData.x = obj2Data.x + obj2Data.width 144 | objData.speedx = 0 145 | changedspeed = true 146 | end 147 | 148 | if obj2Data.rightCollide then 149 | changedspeed = obj2Data:rightCollide(objName, objData) --Item 2 collides.. 150 | if changedspeed ~= false then 151 | if obj2Data.speedx > 0 then 152 | obj2Data.speedx = 0 153 | end 154 | end 155 | else 156 | if obj2Data.speedx > 0 then 157 | obj2Data.speedx = 0 158 | end 159 | end 160 | end 161 | 162 | return changedspeed 163 | end 164 | 165 | function verticalCollide(objName, objData, obj2Name, obj2Data) 166 | local changedspeed = true 167 | 168 | if objData.speedy > 0 then 169 | if objData.downCollide then --first object collision 170 | changedspeed = objData:downCollide(obj2Name, obj2Data) 171 | 172 | if changedspeed ~= false then 173 | objData.y = obj2Data.y - objData.height 174 | objData.speedy = 0 175 | end 176 | else 177 | objData.y = obj2Data.y - objData.height 178 | objData.speedy = 0 179 | changedspeed = true 180 | end 181 | 182 | if obj2Data.upCollide then --opposing object collides 183 | changedspeed = obj2Data:upCollide(objName, objData) --Item 2 collides.. 184 | if changedspeed ~= false then 185 | if obj2Data.speedy < 0 then 186 | obj2Data.speedy = 0 187 | end 188 | end 189 | else 190 | if obj2Data.speedy < 0 then 191 | obj2Data.speedy = 0 192 | end 193 | end 194 | else 195 | if objData.upCollide then 196 | changedspeed = objData:upCollide(obj2Name, obj2Data) 197 | 198 | if changedspeed ~= false then 199 | objData.y = obj2Data.y + obj2Data.height 200 | objData.speedy = 0 201 | end 202 | else 203 | objData.y = obj2Data.y + obj2Data.height 204 | objData.speedy = 0 205 | changedspeed = true 206 | end 207 | 208 | if obj2Data.downCollide then 209 | changedspeed = obj2Data:downCollide(objName, objData) --Item 2 collides.. 210 | if changedspeed ~= false then 211 | if obj2Data.speedy > 0 then 212 | obj2Data.speedy = 0 213 | end 214 | end 215 | else 216 | if obj2Data.speedy > 0 then 217 | obj2Data.speedy = 0 218 | end 219 | end 220 | end 221 | 222 | return changedspeed 223 | end 224 | 225 | function aabb(v1x, v1y, v1width, v1height, v2x, v2y, v2width, v2height) 226 | local v1farx, v1fary, v2farx, v2fary = v1x + v1width, v1y + v1height, v2x + v2width, v2y + v2height 227 | return v1farx > v2x and v1x < v2farx and v1fary > v2y and v1y < v2fary 228 | end 229 | 230 | function CheckCollision(ax1, ay1, aw, ah, bx1, by1, bw, bh) 231 | local ax2, ay2, bx2, by2 = ax1*scale + aw*scale, ay1*scale + ah*scale, bx1*scale + bw*scale, by1*scale + bh*scale 232 | return ax1*scale < bx2 and ax2 > bx1*scale and ay1*scale < by2 and ay2 > by1*scale 233 | end -------------------------------------------------------------------------------- /lisence.txt: -------------------------------------------------------------------------------- 1 | Lisence Details: 2 | 3 | http://creativecommons.org/licenses/by-nc-sa/4.0/ 4 | 5 | You are free to: 6 | 7 | Share — copy and redistribute the material in any medium or format 8 | Adapt — remix, transform, and build upon the material 9 | 10 | The licensor cannot revoke these freedoms as long as you follow the license terms. 11 | 12 | Under the following terms: 13 | 14 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 15 | 16 | NonCommercial — You may not use the material for commercial purposes. 17 | 18 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 19 | 20 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | function love.load() 2 | --image filter 3 | love.graphics.setDefaultFilter("nearest", "nearest") 4 | 5 | --auto require cause lazy 6 | local luaFiles = love.filesystem.getDirectoryItems("") 7 | 8 | for k = 1, #luaFiles do 9 | if love.filesystem.isFile(luaFiles[k]) then 10 | if luaFiles[k] ~= "main.lua" and luaFiles[k] ~= "conf.lua" and luaFiles[k]:sub(-4) == ".lua" then 11 | require(luaFiles[k]:gsub(".lua", "")) 12 | end 13 | end 14 | end 15 | 16 | --images 17 | floorTile = love.graphics.newImage("graphics/tile.png") 18 | floorTileData = love.image.newImageData("graphics/tile.png") 19 | floorQuads = {} 20 | 21 | for y = 1, floorTile:getHeight() / 17 do 22 | for x = 1, floorTile:getWidth() / 17 do 23 | table.insert(floorQuads, love.graphics.newQuad((x - 1) * 17, (y - 1) * 17, 16, 16, floorTile:getWidth(), floorTile:getHeight())) 24 | end 25 | end 26 | 27 | playerimg = love.graphics.newImage("graphics/player.png") 28 | 29 | gameBatch = love.graphics.newSpriteBatch(floorTile, 100) 30 | 31 | antivirusrocket = love.graphics.newImage("graphics/antivirus.png") 32 | antivirusquads = {} 33 | for k = 1, 10 do 34 | antivirusquads[k] = love.graphics.newQuad((k - 1) * 10, 0, 9, 9, antivirusrocket:getWidth(), antivirusrocket:getHeight()) 35 | end 36 | gameoverimg = love.graphics.newImage("graphics/gameover.png") 37 | 38 | proxyintro = love.graphics.newImage("graphics/proxy_intro.png") 39 | proxyintroquads = {} 40 | for k = 1, 9 do 41 | proxyintroquads[k] = love.graphics.newQuad((k - 1) * 10, 0, 9, 9, proxyintro:getWidth(), proxyintro:getHeight()) 42 | end 43 | 44 | proxyimg = love.graphics.newImage("graphics/proxy.png") 45 | proxyquads = {} 46 | for k = 1, 2 do 47 | proxyquads[k] = love.graphics.newQuad((k - 1) * 10, 0, 9, 7, proxyimg:getWidth(), proxyimg:getHeight()) 48 | end 49 | 50 | firewallimg = love.graphics.newImage("graphics/firewall.png") 51 | firewallquads = {} 52 | for k = 1, 8 do 53 | firewallquads[k] = love.graphics.newQuad((k - 1) * 17, 0, 16, 16, firewallimg:getWidth(), firewallimg:getHeight()) 54 | end 55 | 56 | --music 57 | bgm = love.audio.newSource("audio/bgm.ogg") 58 | bgm:setLooping(true) 59 | --bgm:play() 60 | bgm_start = love.audio.newSource("audio/bgm-start.ogg") 61 | bgm_start:setLooping(true) 62 | bgm_start:play() 63 | 64 | gameoversnd = love.audio.newSource("audio/gameover.ogg") 65 | 66 | hitproxysnd = love.audio.newSource("audio/hitproxy.ogg") 67 | playerspawnsnd = love.audio.newSource("audio/playerspawn.ogg") 68 | 69 | --sfx 70 | explosionsnd = love.audio.newSource("audio/explosion.ogg") 71 | jumpsnd = love.audio.newSource("audio/jump.ogg") 72 | blipsnd = love.audio.newSource("audio/blip.ogg") 73 | 74 | bitsnd = {love.audio.newSource("audio/bit.ogg"), love.audio.newSource("audio/bit2.ogg"), love.audio.newSource("audio/bit3.ogg")} 75 | --other 76 | scale = 2 77 | 78 | currentmap = 1 79 | 80 | backgroundFont = love.graphics.setNewFont("graphics/windows_command_prompt.ttf", 16 * scale) 81 | consoleFont = love.graphics.newFont("graphics/windows_command_prompt.ttf", 8 * scale) 82 | winFont = love.graphics.newFont("graphics/windows_command_prompt.ttf", 12 * scale) 83 | 84 | love.window.setMode(17 * 16 * scale, 12 * 16 * scale) 85 | love.window.setTitle("Hax0r?") 86 | love.window.setIcon(love.image.newImageData("graphics/icon.png")) 87 | 88 | gameFunctions.changeState("menu") 89 | 90 | gameMap = { {"H", "&", 0, 1}, {"A", "@", 0, 1}, {"X", "%", 0, 1}, {"0", "#", 0, 1}, {"R", "*", 0, 1}, {"?", "!", 0, 1} } 91 | end 92 | 93 | function love.update(dt) 94 | dt = math.min(1/60, dt) 95 | 96 | if _G[state .. "_update"] then 97 | _G[state .. "_update"](dt) 98 | end 99 | end 100 | 101 | function love.draw() 102 | if _G[state .. "_draw"] then 103 | _G[state .. "_draw"]() 104 | end 105 | end 106 | 107 | function love.keypressed(key) 108 | if _G[state .. "_keypressed"] then 109 | _G[state .. "_keypressed"](key) 110 | end 111 | end 112 | 113 | function love.keyreleased(key) 114 | if _G[state .. "_keyreleased"] then 115 | _G[state .. "_keyreleased"](key) 116 | end 117 | end 118 | 119 | gameFunctions = {} 120 | function gameFunctions.changeState(newState, ...) 121 | local arg = {...} 122 | 123 | state = newState 124 | 125 | if _G[state .. "_init"] then 126 | _G[state .. "_init"](unpack(arg)) 127 | end 128 | end 129 | 130 | function gameFunctions.getWidth() 131 | return 17 * 16 132 | end 133 | 134 | function gameFunctions.getHeight() 135 | return 12 * 16 136 | end 137 | 138 | function love.focus(f) 139 | if not f and not gameover then 140 | paused = true 141 | end 142 | end -------------------------------------------------------------------------------- /maps/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TurtleP/Hax0r/eb005fcf7d31199b3977c89ee865b387493bf150/maps/1.png -------------------------------------------------------------------------------- /mobile/andralog.lua: -------------------------------------------------------------------------------- 1 | function newAnalog(Ax, Ay, Ar, Br, Bd) 2 | local analog = {} 3 | analog.cx = Ax or 200 4 | analog.cy = Ay 5 | analog.deadzone = Bd or 20/100 --Range from 0 to 1 6 | analog.button = Br or 30 7 | analog.size = Ar or 100 8 | analog.angle = 0 9 | analog.d = 0 --Range from 0 to 1 10 | 11 | analog.dx = 0 --Range from 0 to 1 12 | analog.dy = 0 --Range from 0 to 1 13 | 14 | analog.held = false 15 | analog.releasePos = 0 16 | analog.releaseTimer = 0 17 | analog.releaseSpeed = .2 18 | 19 | function analog:getAngle(cx, cy, x, y) 20 | local a = math.atan2(y-cy, x-cx) 21 | a = -a 22 | while a < 0 do 23 | a = a + math.pi*2 24 | end 25 | while a >= math.pi*2 do 26 | a = a - math.pi*2 27 | end 28 | 29 | return a 30 | end 31 | 32 | function analog:fade(currenttime, maxtime, c1, c2) 33 | local tp = currenttime/maxtime 34 | local ret = {} --return color 35 | 36 | for i = 1, #c1 do 37 | ret[i] = c1[i]+(c2[i]-c1[i])*tp 38 | ret[i] = math.max(ret[i], 0) 39 | ret[i] = math.min(ret[i], 255) 40 | end 41 | 42 | return unpack(ret) 43 | end 44 | 45 | function analog:distance(cx, cy, x, y) 46 | return math.sqrt( math.abs(x-cx)^2 + math.abs(y-cy)^2 ) 47 | end 48 | 49 | function analog:renderGradient(size, c1, c2) 50 | local i = love.image.newImageData(size*2, size*2) 51 | for x = 0, size*2-1 do 52 | for y = 0, size*2-1 do 53 | local d = self:distance(size, size, x+1, y+1) 54 | local f = d/size 55 | f = math.max(0, f) 56 | i:setPixel(x, y, self:fade(f, 1, c1, c2)) 57 | end 58 | end 59 | return love.graphics.newImage(i) 60 | end 61 | 62 | function analog:pokedStencil(cx, cy, d1, d2, s) 63 | for a = 0, s-1 do 64 | local p1x = math.cos(a/s*(math.pi*2))*d2 65 | local p1y = -math.sin(a/s*(math.pi*2))*d2 66 | 67 | local p2x = math.cos(a/s*(math.pi*2))*d1 68 | local p2y = -math.sin(a/s*(math.pi*2))*d1 69 | 70 | local p3x = math.cos((a+1)/s*(math.pi*2))*d1 71 | local p3y = -math.sin((a+1)/s*(math.pi*2))*d1 72 | 73 | local p4x = math.cos((a+1)/s*(math.pi*2))*d2 74 | local p4y = -math.sin((a+1)/s*(math.pi*2))*d2 75 | 76 | love.graphics.polygon("fill", cx+p1x, cy+p1y, cx+p2x, cy+p2y, cx+p3x, cy+p3y, cx+p4x, cy+p4y) 77 | end 78 | end 79 | 80 | analog.gradientImage = analog:renderGradient(analog.size, {42, 42, 42, 240}, {255, 255, 255, 55}) 81 | 82 | function analog:draw() 83 | --self screen 84 | local t = self 85 | love.graphics.setColor(255, 255, 255, 155) 86 | love.graphics.circle("line", t.cx, t.cy, t.size, 32) 87 | love.graphics.circle("line", t.cx, t.cy, t.deadzone*t.size, 32) 88 | 89 | love.graphics.setStencil( function() self:pokedStencil(t.cx, t.cy, t.deadzone*t.size, t.size, 32) end) 90 | love.graphics.setColor(255, 255, 255, 255) 91 | love.graphics.draw(self.gradientImage, t.cx-t.size, t.cy-t.size) 92 | love.graphics.setStencil() 93 | 94 | local ax, ay = t.cx + math.cos(t.angle)*t.d*t.size, t.cy - math.sin(t.angle)*t.d*t.size 95 | love.graphics.setInvertedStencil( function() love.graphics.circle("fill", ax, ay, t.button, 32) end ) 96 | local l = love.graphics.getLineWidth() 97 | love.graphics.setLineWidth(12) 98 | love.graphics.setColor({42, 42, 42, 240}) 99 | love.graphics.line(ax, ay, t.cx, t.cy) 100 | love.graphics.circle("fill", t.cx, t.cy, 12/2, 32) 101 | love.graphics.setLineWidth(l) 102 | love.graphics.setInvertedStencil() 103 | 104 | love.graphics.setColor({42, 42, 42, 240}) 105 | love.graphics.circle("fill", ax, ay, t.button, 32) 106 | love.graphics.setColor(255, 255, 255, 255) 107 | love.graphics.circle("line", ax, ay, t.button, 32) 108 | end 109 | 110 | function analog:update(dt) 111 | --Actual code 112 | 113 | --Restore self to center if not being held 114 | if self.releaseTimer > 0 then 115 | self.releaseTimer = math.max(0, self.releaseTimer-dt) 116 | end 117 | 118 | if not self.held then 119 | self.d = math.max(0, self.releasePos*(self.releaseTimer/self.releaseSpeed) ) 120 | end 121 | end 122 | 123 | --they check for pressure > .5 124 | function analog:touchPressed(id, x, y, pressure) 125 | if pressure > 0.5 then 126 | local d = self:distance(x, y, self.cx + math.cos(self.angle)*self.d*self.size, self.cy - math.sin(self.angle)*self.d*self.size) 127 | if d <= self.button then 128 | self.held = id 129 | self:touchMoved(id, x, y, pressure) 130 | end 131 | end 132 | end 133 | 134 | function analog:touchReleased(id, x, y, pressure) 135 | --local x, y = x*love.window.getWidth(), y*love.window.getHeight() 136 | if pressure > .5 then 137 | if self.held == id then 138 | self.held = false 139 | self.releaseTimer = self.releaseSpeed 140 | self.releasePos = self.d 141 | self.dx = 0 142 | self.dy = 0 143 | end 144 | end 145 | end 146 | --Yee 147 | 148 | function analog:touchMoved(id, x, y, pressure) 149 | if pressure > .5 then 150 | if self.held == id then 151 | local d = self:distance(x, y, self.cx, self.cy) 152 | self.d = math.min(1, d/self.size) 153 | self.angle = self:getAngle(self.cx, self.cy, x, y) 154 | if self.d >= self.deadzone then 155 | self.dx = math.cos(self.angle) * (self.d-self.deadzone)/(1-self.deadzone) 156 | self.dy = -math.sin(self.angle) * (self.d-self.deadzone)/(1-self.deadzone) 157 | else 158 | self.dx = 0 159 | self.dy = 0 160 | end 161 | end 162 | end 163 | end 164 | 165 | function analog:getX() 166 | return self.dx 167 | end 168 | 169 | function analog:getY() 170 | return self.dy 171 | end 172 | 173 | function analog:isHeld() 174 | return self.held 175 | end 176 | 177 | return analog 178 | end -------------------------------------------------------------------------------- /mobile/mobile.lua: -------------------------------------------------------------------------------- 1 | mobile = 2 | { 3 | analogtimer = 0 4 | } 5 | 6 | analog = newAnalog(160, love.window.getHeight() - 180, 100, 50) 7 | pause = newVirtualButton(love.window.getWidth() / gameFunctions.getFullScreenScale() - 30, 20, 16, "||", controls["pause"], nil, true) 8 | mobileDelay = 1/60 --dt 9 | 10 | local oldupdate = love.update 11 | function love.update(dt) 12 | oldupdate(dt) 13 | 14 | if state == "game" then 15 | analog:update(dt) 16 | 17 | if analog:isHeld() then 18 | if analog:getX() > 0.5 then 19 | love.keypressed(controls["right"]) 20 | end 21 | 22 | if analog:getX() >= 0 and analog:getX() <= 0.5 then 23 | love.keyreleased(controls["right"]) 24 | end 25 | 26 | if analog:getX() < -0.5 then 27 | love.keypressed(controls["left"]) 28 | end 29 | 30 | if analog:getX() >= -0.5 and analog:getX() <= 0 then 31 | love.keyreleased(controls["left"]) 32 | end 33 | 34 | if analog:getY() > 0.5 then 35 | mobile.analogtimer = math.min(mobile.analogtimer + dt, dt) 36 | end 37 | else 38 | love.keyreleased(controls["right"]) 39 | love.keyreleased(controls["left"]) 40 | end 41 | else 42 | if not showCredits then 43 | if mobileDelay > 0 then 44 | mobileDelay = mobileDelay - dt 45 | end 46 | else 47 | mobileDelay = dt 48 | end 49 | end 50 | end 51 | 52 | local olddraw = love.draw 53 | function love.draw() 54 | olddraw() 55 | 56 | if state == "game" then 57 | analog:draw() 58 | end 59 | 60 | pause:draw() 61 | end 62 | 63 | function love.touchmoved(id, x, y, pressure) 64 | local x, y = x*love.graphics.getWidth(), y*love.graphics.getHeight() 65 | 66 | if state == "game" then 67 | analog:touchMoved(id, x, y, pressure) 68 | end 69 | end 70 | 71 | function love.touchpressed(id, x, y, pressure) 72 | local x, y = x*love.graphics.getWidth(), y*love.graphics.getHeight() 73 | 74 | if state == "game" then 75 | analog:touchPressed(id, x, y, pressure) 76 | end 77 | 78 | pause:touchPressed(id, x, y, pressure) 79 | 80 | if pressure > 0.5 then 81 | if state == "game" then 82 | if not CheckCollision(pause.boundsX, pause.boundsY, pause.width, pause.height, x / scale, y / scale, 8, 8) and not CheckCollision(analog.cx - analog.size, analog.cy - analog.size, analog.size * 2, analog.size * 2, x / scale, y / scale, 8, 8) and analog.held ~= id then 83 | if not paused then 84 | love.keypressed(controls["jump"]) 85 | end 86 | end 87 | 88 | if paused then 89 | local canPress = false 90 | for k = 1, #pauseMenu.items do 91 | local v = pauseMenu 92 | 93 | local x = (v.x + v.width / 2) - (pauseFont:getWidth(v.items[k]) / scale) / 2 94 | local y = ((v.y + 20) + (k - 1) * 14) 95 | 96 | 97 | 98 | if CheckCollision(x, y, pauseFont:getWidth(v.items[k]) / scale, pauseFont:getHeight(v.items[k]) / scale, x / scale, y / scale, 8, 8) then 99 | pauseMenu.itemi = k 100 | else 101 | if not CheckCollision(pauseMenu.x, pauseMenu.y, pauseMenu.width, pauseMenu.height, x / scale, y / scale, 8, 8) then 102 | canPress = true 103 | end 104 | end 105 | end 106 | 107 | if canPress then 108 | love.keypressed(controls["jump"]) 109 | end 110 | end 111 | else 112 | local canPress = false 113 | for k = 1, #titleThings do 114 | local v = titleThings[k][1] 115 | 116 | if CheckCollision(1, (120 + (k - 1) * 14), backgroundFont:getWidth(v) / scale, backgroundFont:getHeight(v) / scale, x / scale, y / scale, 8, 8) then 117 | menui = k 118 | else 119 | if not CheckCollision(0, 120, backgroundFont:getWidth("> " .. titleThings[2][1]) / scale, 162, x / scale, y / scale, 8, 8) then 120 | canPress = true 121 | end 122 | end 123 | end 124 | 125 | if canPress then 126 | love.keypressed(controls["jump"]) 127 | end 128 | end 129 | end 130 | end 131 | 132 | function love.touchreleased(id, x, y, pressure) 133 | local x, y = x*love.graphics.getWidth(), y*love.graphics.getHeight() 134 | 135 | pause:touchReleased(id, x, y, pressure) 136 | analog:touchReleased(id, x, y, pressure) 137 | end -------------------------------------------------------------------------------- /mobile/virtualbutton.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Virtual Button 3 | 4 | Makes it so there's buttons to tap 5 | Fancy stuff. Yeh. 6 | --]] 7 | 8 | function newVirtualButton(x, y, r, text, key, backKey, gameOnly) 9 | local virtualbutton = {} 10 | 11 | virtualbutton.x = x 12 | virtualbutton.y = y 13 | virtualbutton.text = text 14 | virtualbutton.key = key 15 | virtualbutton.r = r 16 | 17 | virtualbutton.backKeyData = backKey 18 | 19 | virtualbutton.boundsX = x - r 20 | virtualbutton.boundsY = y - r 21 | 22 | virtualbutton.width = r * 2 23 | virtualbutton.height = virtualbutton.width 24 | 25 | virtualbutton.gameOnly = gameOnly 26 | 27 | virtualbutton.colors = 28 | { 29 | ["true"] = {255, 255, 255, 200}, 30 | ["false"] = {42, 42, 42, 200} 31 | } 32 | 33 | virtualbutton.pressed = false 34 | 35 | virtualbutton.id = 0 36 | 37 | local function toboolean(b) 38 | if type(b) == "string" then 39 | if b == "true" then 40 | return true 41 | end 42 | return false 43 | end 44 | end 45 | 46 | function virtualbutton:setID(id) 47 | self.id = id + 1 48 | end 49 | 50 | function virtualbutton:setPos(x, y) 51 | self.x, self.y = x, y 52 | self.boundsX = x - self.r 53 | self.boundsY = y - self.r 54 | end 55 | 56 | function virtualbutton:touchPressed(id, x, y, pressure) 57 | if self.gameOnly and state ~= "game" then 58 | return 59 | end 60 | 61 | if CheckCollision(self.boundsX, self.boundsY, self.width, self.height, x / scale, y / scale, 8, 8) then 62 | self.pressed = true 63 | 64 | self:setID(id) 65 | 66 | if self.backKeyData and not self.key then 67 | love.keypressed(self.backKeyData) 68 | elseif self.key and not self.backKeyData then 69 | love.keypressed(self.key) 70 | elseif self.key and self.backKeyData then 71 | if state ~= "game" or (state == "game" and paused) then 72 | love.keypressed(self.backKeyData) 73 | else 74 | love.keypressed(self.key) 75 | end 76 | end 77 | end 78 | end 79 | 80 | function virtualbutton:touchReleased(id, x, y, pressure) 81 | if self.gameOnly and state ~= "game" then 82 | return 83 | end 84 | 85 | if self.pressed then 86 | if self.id == id + 1 then 87 | self.pressed = false 88 | end 89 | end 90 | end 91 | 92 | function virtualbutton:draw() 93 | if self.gameOnly and state ~= "game" then 94 | return 95 | end 96 | 97 | love.graphics.setFont(winFont) 98 | 99 | love.graphics.setColor(self.colors[tostring(self.pressed)]) 100 | love.graphics.circle("fill", self.x * scale, self.y * scale, self.r * scale) 101 | 102 | love.graphics.setColor(self.colors[tostring(not self.pressed)]) 103 | love.graphics.print(self.text, (self.boundsX + self.width / 2) * scale - winFont:getWidth(self.text) / 2, (self.boundsY + self.height / 2) * scale - winFont:getHeight(self.text) / 2) 104 | 105 | --self:debugDraw() 106 | end 107 | 108 | return virtualbutton 109 | end -------------------------------------------------------------------------------- /physics.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Turtle's Physics Library 3 | All code is mine. 4 | (c) 2015 Tiny Turtle Industries 5 | (Obviously same licensing as the game) 6 | --]] 7 | 8 | function physicsupdate(dt) 9 | local obj = objects 10 | 11 | for name, objectT in pairs(obj) do 12 | if name ~= "tile" then --not updating tiles! 13 | for _, objData in pairs(objectT) do --check object variables 14 | if objData.active and not objData.static then 15 | 16 | local hor, ver = false, false 17 | 18 | objData.speedy = math.min(objData.speedy + objData.gravity * dt, 10 * 16) --add gravity to objects 19 | 20 | for name2, object2T in pairs(obj) do 21 | if objData.mask[name2] == true and not objData.passive then 22 | hor, ver = checkCollision(objectT, object2T, objData, name, name2, dt) 23 | else 24 | checkPassive(objectT, object2T, objData, name, name2, dt) 25 | end 26 | end 27 | 28 | if not hor then 29 | objData.x = objData.x + objData.speedx * dt 30 | end 31 | 32 | if not ver then 33 | objData.y = objData.y + objData.speedy * dt 34 | end 35 | end 36 | end 37 | end 38 | end 39 | end 40 | 41 | function checkRectangle(x, y, w, h, obj) 42 | 43 | if type(obj) == "string" then 44 | for k, v in pairs(objects[obj]) do 45 | if aabb(x, y, w, h, v.x, v.y, v.width, v.height) then 46 | return true 47 | end 48 | end 49 | return false 50 | else 51 | for k = 1, #obj do 52 | local v = obj[k] 53 | for j, v in pairs(objects[v]) do 54 | if aabb(x, y, w, h, v.x, v.y, v.width, v.height) then 55 | return true 56 | end 57 | end 58 | end 59 | return false 60 | end 61 | 62 | end 63 | 64 | function checkPassive(objTable, obj2Table, objData, objName, obj2Name, dt) 65 | for _, obj2Data in pairs(obj2Table) do 66 | if aabb(objData.x, objData.y + objData.speedy * dt, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) or aabb(objData.x + objData.speedx * dt, objData.y, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then --was vertical 67 | if objData.passiveCollide then 68 | objData:passiveCollide(obj2Name, obj2Data) 69 | end 70 | end 71 | end 72 | end 73 | 74 | function checkCollision(objTable, obj2Table, objData, objName, obj2Name, dt) 75 | local hor, ver = false, false 76 | 77 | for _, obj2Data in pairs(obj2Table) do 78 | if not obj2Data.passive then 79 | 80 | if aabb(objData.x + objData.speedx * dt, objData.y + objData.speedy * dt, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then 81 | 82 | if aabb(objData.x, objData.y + objData.speedy * dt, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then --was vertical 83 | ver = verticalCollide(objName, objData, obj2Name, obj2Data) 84 | elseif aabb(objData.x + objData.speedx * dt, objData.y, objData.width, objData.height, obj2Data.x, obj2Data.y, obj2Data.width, obj2Data.height) then 85 | hor = horizontalCollide(objName, objData, obj2Name, obj2Data) 86 | else 87 | --dat bug doe 88 | --[[if (objData.speedy - objData.gravity * dt) < (objData.speedx) then 89 | ver = verticalCollide(objName, objData, obj2Name, obj2Data) 90 | else 91 | hor = horizontalCollide(objName, objData, obj2Name, obj2Data) 92 | end]] 93 | end 94 | 95 | end 96 | 97 | else 98 | checkPassive(objTable, obj2Table, objData, objName, obj2Name, dt) 99 | hor = false 100 | ver = false 101 | end 102 | end 103 | 104 | return hor, ver 105 | end 106 | 107 | function horizontalCollide(objName, objData, obj2Name, obj2Data) 108 | local changedspeed = true 109 | 110 | if objData.speedx > 0 then 111 | if objData.rightCollide then --first object collision 112 | changedspeed = objData:rightCollide(obj2Name, obj2Data) 113 | if changedspeed ~= false then 114 | objData.x = obj2Data.x - objData.width 115 | objData.speedx = 0 116 | end 117 | else 118 | objData.x = obj2Data.x - objData.width 119 | objData.speedx = 0 120 | changedspeed = true 121 | end 122 | 123 | if obj2Data.leftCollide then --opposing object collides 124 | changedspeed = obj2Data:leftCollide(objName, objData) --Item 2 collides.. 125 | if changedspeed ~= false then 126 | if obj2Data.speedx < 0 then 127 | obj2Data.speedx = 0 128 | end 129 | end 130 | else 131 | if obj2Data.speedx < 0 then 132 | obj2Data.speedx = 0 133 | end 134 | end 135 | else 136 | if objData.leftCollide then 137 | changedspeed = objData:leftCollide(obj2Name, obj2Data) 138 | if changedspeed ~= false then 139 | objData.x = obj2Data.x + obj2Data.width 140 | objData.speedx = 0 141 | end 142 | else 143 | objData.x = obj2Data.x + obj2Data.width 144 | objData.speedx = 0 145 | changedspeed = true 146 | end 147 | 148 | if obj2Data.rightCollide then 149 | changedspeed = obj2Data:rightCollide(objName, objData) --Item 2 collides.. 150 | if changedspeed ~= false then 151 | if obj2Data.speedx > 0 then 152 | obj2Data.speedx = 0 153 | end 154 | end 155 | else 156 | if obj2Data.speedx > 0 then 157 | obj2Data.speedx = 0 158 | end 159 | end 160 | end 161 | 162 | return changedspeed 163 | end 164 | 165 | function verticalCollide(objName, objData, obj2Name, obj2Data) 166 | local changedspeed = true 167 | 168 | if objData.speedy > 0 then 169 | if objData.downCollide then --first object collision 170 | changedspeed = objData:downCollide(obj2Name, obj2Data) 171 | 172 | if changedspeed ~= false then 173 | objData.y = obj2Data.y - objData.height 174 | objData.speedy = 0 175 | end 176 | else 177 | objData.y = obj2Data.y - objData.height 178 | objData.speedy = 0 179 | changedspeed = true 180 | end 181 | 182 | if obj2Data.upCollide then --opposing object collides 183 | changedspeed = obj2Data:upCollide(objName, objData) --Item 2 collides.. 184 | if changedspeed ~= false then 185 | if obj2Data.speedy < 0 then 186 | obj2Data.speedy = 0 187 | end 188 | end 189 | else 190 | if obj2Data.speedy < 0 then 191 | obj2Data.speedy = 0 192 | end 193 | end 194 | else 195 | if objData.upCollide then 196 | changedspeed = objData:upCollide(obj2Name, obj2Data) 197 | 198 | if changedspeed ~= false then 199 | objData.y = obj2Data.y + obj2Data.height 200 | objData.speedy = 0 201 | end 202 | else 203 | objData.y = obj2Data.y + obj2Data.height 204 | objData.speedy = 0 205 | changedspeed = true 206 | end 207 | 208 | if obj2Data.downCollide then 209 | changedspeed = obj2Data:downCollide(objName, objData) --Item 2 collides.. 210 | if changedspeed ~= false then 211 | if obj2Data.speedy > 0 then 212 | obj2Data.speedy = 0 213 | end 214 | end 215 | else 216 | if obj2Data.speedy > 0 then 217 | obj2Data.speedy = 0 218 | end 219 | end 220 | end 221 | 222 | return changedspeed 223 | end 224 | 225 | function aabb(v1x, v1y, v1width, v1height, v2x, v2y, v2width, v2height) 226 | local v1farx, v1fary, v2farx, v2fary = v1x + v1width, v1y + v1height, v2x + v2width, v2y + v2height 227 | return v1farx > v2x and v1x < v2farx and v1fary > v2y and v1y < v2fary 228 | end -------------------------------------------------------------------------------- /player.lua: -------------------------------------------------------------------------------- 1 | function newPlayer(x, y, fadein) 2 | local player = {} 3 | 4 | player.x = x 5 | player.y = y 6 | player.width = 16 7 | player.height = 16 8 | 9 | player.pointingangle = 0 10 | 11 | player.rightkey = false 12 | player.upkey = false 13 | player.downkey = false 14 | player.leftkey = false 15 | 16 | player.speedx = 0 17 | player.speedy = 0 18 | player.active = true 19 | player.gravity = 400 20 | 21 | player.mask = 22 | { 23 | ["tile"] = true, 24 | ["bit"] = true, 25 | ["antivirus"] = true 26 | } 27 | 28 | playerspawnsnd:play() 29 | 30 | player.quads = {} 31 | 32 | for k = 1, 4 do 33 | player.quads[k] = love.graphics.newQuad((k - 1) * 17, 0, 16, 19, playerimg:getWidth(), playerimg:getHeight()) 34 | end 35 | 36 | player.quadi = 1 37 | player.timer = 0 38 | player.rate = 8 39 | 40 | player.fade = 1 41 | player.fadeOut = false 42 | player.jumping = false 43 | 44 | player.fadeOut = fadein or false 45 | 46 | if fadein then 47 | player.fade = 0 48 | end 49 | 50 | function player:update(dt) 51 | if not self.rightkey and not self.leftkey and not self.downkey and not self.upkey then 52 | self.speedx = 0 53 | elseif self.rightkey then 54 | self.speedx = 60 55 | elseif self.leftkey then 56 | self.speedx = -60 57 | end 58 | 59 | self.timer = self.timer + self.rate * dt 60 | self.quadi = math.floor(self.timer%4)+1 61 | 62 | if self.fade ~= 1 then 63 | self.fade = math.min(1, self.fade + dt) 64 | self.speedx = 0 65 | self.speedy = 0 66 | end 67 | end 68 | 69 | function player:draw() 70 | love.graphics.setColor(255, 255, 255, 255 * self.fade) 71 | love.graphics.draw(playerimg, self.quads[self.quadi], self.x * scale, self.y * scale, 0, scale, scale, 0, 3) 72 | end 73 | 74 | function player:moveright(move) 75 | self.rightkey = move 76 | end 77 | 78 | function player:moveleft(move) 79 | self.leftkey = move 80 | end 81 | 82 | function player:jump(shortHop) 83 | if not self.jumping and not shortHop then 84 | self.speedy = -160 85 | self.jumping = true 86 | 87 | jumpsnd:play() 88 | else 89 | if shortHop then 90 | self.speedy = -120 91 | self.jumping = true 92 | end 93 | end 94 | end 95 | 96 | function player:downCollide(name, data) 97 | if name == "bit" or name == "proxy" then 98 | if self.speedy > 0 then 99 | self:jump(true) 100 | 101 | if name == "bit" then 102 | data:die() 103 | elseif name == "proxy" then 104 | data.gravity = 180 105 | hitproxysnd:play() 106 | end 107 | 108 | combo = combo + 1 109 | end 110 | return false 111 | end 112 | 113 | if name == "firewall" then 114 | if data.fade == 1 then 115 | self:die() 116 | else 117 | return false 118 | end 119 | end 120 | 121 | if name == "antivirus" then 122 | self:die() 123 | end 124 | 125 | self.jumping = false 126 | end 127 | 128 | function player:upCollide(name, data) 129 | if name == "bit" or name == "proxy" then 130 | return false 131 | end 132 | 133 | if name == "firewall" then 134 | if data.fade == 1 then 135 | self:die() 136 | else 137 | return false 138 | end 139 | end 140 | 141 | if name == "antivirus" then 142 | self:die() 143 | end 144 | end 145 | 146 | function player:leftCollide(name, data) 147 | if name == "bit" or name == "proxy" then 148 | return false 149 | end 150 | 151 | if name == "tile" then 152 | if love.keyboard.isDown("a") then 153 | self.speedy = -60 154 | end 155 | end 156 | 157 | if name == "firewall" then 158 | if data.fade == 1 then 159 | self:die() 160 | else 161 | return false 162 | end 163 | end 164 | 165 | if name == "antivirus" then 166 | self:die() 167 | end 168 | end 169 | 170 | function player:rightCollide(name, data) 171 | if name == "bit" or name == "proxy" then 172 | return false 173 | end 174 | 175 | if name == "tile" then 176 | if love.keyboard.isDown("d") then 177 | self.speedy = -60 178 | end 179 | end 180 | 181 | if name == "firewall" then 182 | if data.fade == 1 then 183 | self:die() 184 | else 185 | return false 186 | end 187 | end 188 | 189 | if name == "antivirus" then 190 | self:die() 191 | end 192 | end 193 | 194 | function player:die(win) 195 | table.insert(objects["digits"], newDeath(self.x + self.width / 2 - 4, self.y - 3)) 196 | self.remove = true 197 | 198 | --obviously 199 | if not win then 200 | gameover = true 201 | end 202 | end 203 | 204 | return player 205 | end 206 | 207 | function newDeath(x, y) 208 | local death = {} 209 | 210 | local deathn = {} 211 | local values = {"0", "1"} 212 | for k = 1, 6 do 213 | deathn[k] = { x = x , y = y + (k - 1) * 6 , value = values[love.math.random(#values)], speed = (math.random() * 2 - 1) * 40, timer = 0 } 214 | end 215 | 216 | death.x = x 217 | death.y = y 218 | death.width = 16 219 | death.height = 16 220 | 221 | gameoversnd:play() 222 | 223 | function death:update(dt) 224 | for k = 1, #deathn do 225 | deathn[k].x = deathn[k].x + deathn[k].speed * dt 226 | 227 | if deathn[k].timer < 0.8 then 228 | deathn[k].timer = deathn[k].timer + dt 229 | deathn[k].y = deathn[k].y - 30 * dt 230 | else 231 | deathn[k].y = deathn[k].y + 30 * dt 232 | end 233 | end 234 | end 235 | 236 | function death:draw() 237 | love.graphics.setFont(consoleFont) 238 | for k = 1, #deathn do 239 | love.graphics.setColor(0, 150, 0) 240 | love.graphics.print(deathn[k].value, deathn[k].x * scale, deathn[k].y * scale) 241 | end 242 | end 243 | 244 | return death 245 | end -------------------------------------------------------------------------------- /proxy.lua: -------------------------------------------------------------------------------- 1 | function newProxy(x, y) 2 | local proxy = {} 3 | 4 | proxy.x = x 5 | proxy.y = y 6 | 7 | local spd = {-40, 40} 8 | proxy.speed = 50 9 | proxy.speedy = 0 10 | proxy.gravity = 0 11 | proxy.speedx = proxy.speed 12 | 13 | proxy.active = true 14 | 15 | proxy.mask = { ["tile"] = true, ["player"] = true } 16 | 17 | proxy.width = 9 18 | proxy.height = 9 19 | 20 | proxy.quadi = 1 21 | proxy.timer = 0 22 | 23 | proxy.intro = true 24 | 25 | proxy.turnAround = {false, false} 26 | 27 | function proxy:update(dt) 28 | if self.intro then 29 | if self.quadi < #proxyintroquads then 30 | self.timer = self.timer + 8 * dt 31 | self.quadi = math.floor(self.timer%#proxyintroquads)+1 32 | else 33 | self.timer = 0 34 | self.intro = false 35 | self.quadi = 1 36 | end 37 | else 38 | self.timer = self.timer + 4 * dt 39 | self.quadi = math.floor(self.timer%#proxyquads)+1 40 | end 41 | 42 | if self.turnAround[1] or self.turnAround[2] then 43 | if self.turnAround[1] then 44 | self.speedx = -self.speed 45 | self.turnAround[1] = false 46 | else 47 | self.speedx = self.speed 48 | self.turnAround[2] = false 49 | end 50 | end 51 | end 52 | 53 | function proxy:upCollide(name, data) 54 | if name == "player" then 55 | return false 56 | end 57 | end 58 | 59 | function proxy:leftCollide(name, data) 60 | if name == "tile" then 61 | self.turnAround[2] = true 62 | end 63 | 64 | if name == "player" then 65 | return false 66 | end 67 | end 68 | 69 | function proxy:rightCollide(name, data) 70 | if name == "tile" then 71 | self.turnAround[1] = true 72 | end 73 | 74 | if name == "player" then 75 | return false 76 | end 77 | end 78 | 79 | function proxy:downCollide(name, data) 80 | if name == "tile" then 81 | self:die() 82 | end 83 | 84 | if name == "player" then 85 | return false 86 | end 87 | end 88 | 89 | function proxy:die() 90 | if not self.intro then 91 | table.insert(objects["explosion"], newExplosion(self.x, self.y)) 92 | self.remove = true 93 | end 94 | end 95 | 96 | function proxy:draw() 97 | love.graphics.setColor(255, 255, 255, 255) 98 | if self.intro then 99 | love.graphics.draw(proxyintro, proxyintroquads[self.quadi], self.x * scale, self.y * scale, 0, scale, scale) 100 | else 101 | love.graphics.draw(proxyimg, proxyquads[self.quadi], self.x * scale, self.y * scale, 0, scale, scale) 102 | end 103 | end 104 | 105 | return proxy 106 | end -------------------------------------------------------------------------------- /states/game.lua: -------------------------------------------------------------------------------- 1 | function game_init() 2 | loadMap(1) 3 | 4 | score = 0 5 | 6 | backgroundLines = {} 7 | for k = 1, 16 do 8 | backgroundLines[k] = newBackgroundLine() 9 | end 10 | 11 | gameover = false 12 | gameoversin = 0 13 | tremorX = 0 14 | tremorY = 0 15 | 16 | scoreTypes = {"KB", "MB", "GB"} 17 | scorei = 1 18 | 19 | events = { ["proxy"] = false, ["scan"] = {false, false, false}, ["udpopen"] = {false, false} , ["firewall"] = false, ["win"] = true } 20 | 21 | combo = 0 22 | combotimeout = 0 23 | paused = false 24 | end 25 | 26 | function game_update(dt) 27 | if paused then 28 | return 29 | end 30 | 31 | for k, v in pairs(objects) do 32 | for j, w in pairs(v) do 33 | if w.remove then 34 | table.remove(objects[k], j) 35 | end 36 | end 37 | end 38 | 39 | if tremorX and tremorY then 40 | if tremorX > 0 then 41 | tremorX = math.max(tremorX - 10 * dt, 0) 42 | else 43 | tremorX = math.min(tremorX + 10 * dt, 0) 44 | end 45 | 46 | if tremorY > 0 then 47 | tremorY = math.max(tremorY - 10 * dt, 0) 48 | else 49 | tremorY = math.min(tremorY + 10 * dt, 0) 50 | end 51 | end 52 | 53 | if gameover then 54 | gameoversin = gameoversin + dt 55 | 56 | for k, v in pairs(objects["digits"]) do 57 | v:update(dt) 58 | end 59 | 60 | for k, v in pairs(objects["explosion"]) do 61 | v:update(dt) 62 | end 63 | 64 | return 65 | end 66 | 67 | if combo > 1 then 68 | if combotimeout < 1 then 69 | combotimeout = combotimeout + dt 70 | else 71 | combo = 0 72 | combotimeout = 0 73 | end 74 | end 75 | 76 | for k, v in pairs(objects) do 77 | for j, w in pairs(v) do 78 | if w.update then 79 | w:update(dt) 80 | end 81 | end 82 | end 83 | 84 | for k, v in pairs(timers) do 85 | for j, w in pairs(v) do 86 | w:update(dt) 87 | 88 | if w.remove then 89 | table.remove(timers[k], j) 90 | end 91 | end 92 | end 93 | 94 | for k, v in pairs(backgroundLines) do 95 | v.y = v.y + v.speed * dt 96 | 97 | if v.y > gameFunctions.getHeight() then 98 | backgroundLines[k] = newBackgroundLine() 99 | end 100 | end 101 | 102 | if background[currentPos].fadeOut then 103 | background[currentPos].fade = math.max(0, background[currentPos].fade - 160 * dt) 104 | 105 | if positionTimer == 0 then 106 | positionTimer = 0.01 107 | end 108 | else 109 | if positionTimer > 0 then 110 | positionTimer = positionTimer - dt 111 | else 112 | currentPos = love.math.random(#background) 113 | background[currentPos].fadeOut = true 114 | positionTimer = 0.01 115 | end 116 | end 117 | 118 | for k = #background, 1, -1 do 119 | if background[k].fade == 0 then 120 | background[k].fade = 255 121 | background[k].fadeOut = false 122 | end 123 | end 124 | 125 | --events? 126 | if not events["proxy"] then 127 | if score > 20 then 128 | consoleDelay(1, "Proxies detected in traffic. Data flow may be interrupted.", {255, 35, 0}) 129 | table.insert(timers["events"], newRepeatTimer(10, function() 130 | local s = love.math.random(100) 131 | 132 | if s < 20 then 133 | table.insert(objects["proxy"], newProxy(love.math.random(2 * 16, 14 * 16), love.math.random(3 * 16, 6 * 16))) 134 | end 135 | end)) 136 | events["proxy"] = true 137 | end 138 | end 139 | 140 | if not events["udpopen"][1] then 141 | if score > 40 then 142 | consoleDelay(0.3, "Running bin/UDPCrack.sh (4%)") 143 | events["udpopen"][1] = true 144 | end 145 | end 146 | 147 | if not events["udpopen"][2] then 148 | if score > 65 then 149 | consoleDelay(0.3, "Running bin/UDPCrack.sh (60%)") 150 | consoleDelay(6, "Infected machine is doing a virus scan! (5%)", {255, 35, 0}) 151 | events["udpopen"][2] = true 152 | end 153 | end 154 | 155 | if not events["udpopen"][3] then 156 | if score > 160 then 157 | consoleDelay(0.3, "UDPCrack.sh has unloaded port #XX on machine.") 158 | consoleDelay(6, "Dataflow will now increase.") 159 | 160 | timers["bits"][1] = newRepeatTimer(1.5, function() 161 | if #objects["bit"] < 12 and #objects["proxy"] == 0 then 162 | table.insert(objects["bit"], newBit(love.math.random(2 * 16, 15 * 16), love.math.random(2 * 16, 9 * 16))) 163 | end 164 | end) 165 | events["udpopen"][3] = true 166 | end 167 | end 168 | 169 | if not events["scan"][1] then 170 | if score > 105 then 171 | consoleDelay(0.3, "Infected machine is doing a virus scan! (83%)", {255, 35, 0}) 172 | events["scan"][1] = true 173 | end 174 | end 175 | 176 | if not events["scan"][2] then 177 | if score > 130 then 178 | consoleDelay(1, "Infected machine's antivirus has found you!", {255, 35, 0}, function() 179 | table.insert(timers["av"], newRepeatTimer(5, function() 180 | table.insert(objects["antivirus"], newAntivirus(love.math.random(2 * 16, 15 * 16), love.math.random(2 * 16, 3 * 16))) 181 | end)) 182 | end) 183 | events["scan"][2] = true 184 | end 185 | end 186 | 187 | if not events["firewall"] then 188 | if score > 280 then 189 | consoleDelay(1, "Infected machine's firewall has been triggered.", {255, 35, 0}, function() 190 | table.insert(timers["firewall"], newRepeatTimer(8, function() 191 | local s = love.math.random(100) 192 | 193 | if s < 30 then 194 | local x = love.math.random(2, 16) 195 | local y = love.math.random(9, 10) 196 | 197 | table.insert(objects["firewall"], newFirewall((x * 16), (y * 16))) 198 | 199 | local x = love.math.random(2, 16) 200 | local y = love.math.random(9, 10) 201 | 202 | table.insert(objects["firewall"], newFirewall((x * 16), (y * 16))) 203 | end 204 | end)) 205 | end) 206 | events["firewall"] = true 207 | end 208 | end 209 | 210 | --OH FUCK PLOT TWIST 211 | if score == 1024 then 212 | scorei = scorei + 1 213 | score = 1 214 | 215 | consoleDelay(0.3, "Thanks for that. You monster of a virus.", nil, function() 216 | timers["bits"] = {} 217 | timers["av"] = {} 218 | timers["events"] = {} 219 | timers["firewall"] = {} 220 | objects["bit"] = {} 221 | bgm:stop() 222 | end) 223 | consoleDelay(6, "You're nothing to me now.", nil, function() 224 | objects["player"][1]:die(true) 225 | end) 226 | consoleDelay(10, "Running /reboot -3 on remote machine..") 227 | consoleDelay(15, "...", nil, function() 228 | blipsnd:play() 229 | gameFunctions.changeState("win") 230 | end) 231 | end 232 | 233 | physicsupdate(dt) 234 | end 235 | 236 | function game_draw() 237 | for j = 1, #background do 238 | if background[j].fadeOut then 239 | love.graphics.setColor(255, 255, 255, background[j].fade) 240 | love.graphics.print(background[j].value, background[j].x, background[j].y) 241 | end 242 | end 243 | 244 | for k, v in pairs(backgroundLines) do 245 | love.graphics.setColor(v.colors) 246 | love.graphics.rectangle("fill", v.x * scale, v.y * scale, v.width * scale, v.height * scale) 247 | end 248 | 249 | love.graphics.setColor(255, 255, 255, 255) 250 | 251 | love.graphics.push() 252 | 253 | love.graphics.translate(tremorX, tremorY) 254 | love.graphics.draw(gameBatch) 255 | 256 | for k, v in pairs(objects) do 257 | for j, w in pairs(v) do 258 | if w.draw then 259 | w:draw() 260 | end 261 | end 262 | end 263 | 264 | love.graphics.pop() 265 | 266 | love.graphics.setFont(backgroundFont) 267 | 268 | love.graphics.setColor(0, 0, 0, 255) 269 | 270 | love.graphics.print("Score: " .. score .. scoreTypes[scorei] .. " / " .. "1MB", 4 * scale, gameFunctions.getHeight() * scale - backgroundFont:getHeight("Score: " .. score)) 271 | 272 | love.graphics.setColor(255, 255, 255, 255) 273 | if gameover then 274 | love.graphics.draw(gameoverimg, gameFunctions.getWidth() / 2 * scale - (38 / 2) * scale, gameFunctions.getHeight() / 2 * scale - (58 / 2) * scale + math.sin(gameoversin) * 20, 0, scale, scale) 275 | 276 | love.graphics.print("Press 'R' to retry.", gameFunctions.getWidth() / 2 * scale - backgroundFont:getWidth("Press 'R' to retry") / 2, gameFunctions.getHeight() / 2 * scale - backgroundFont:getWidth("Press 'R' to retry") / 2 + 100 * scale + math.sin(gameoversin) * 20) 277 | end 278 | 279 | if paused and not gameover then 280 | love.graphics.print("Game Paused", gameFunctions.getWidth() / 2 * scale - backgroundFont:getWidth("Game Paused") / 2, gameFunctions.getHeight() / 2 * scale - backgroundFont:getHeight("Game Paused") / 2) 281 | end 282 | end 283 | 284 | function game_mousepressed(x, y, button) 285 | 286 | end 287 | 288 | function nextMap() 289 | currentmap = currentmap + 1 290 | 291 | if love.filesystem.exists("graphics/" .. currentmap .. ".png") then 292 | loadMap(currentmap) 293 | else 294 | return 295 | end 296 | end 297 | 298 | function game_keypressed(key) 299 | if key == "escape" then 300 | paused = not paused 301 | end 302 | 303 | if not objects["player"][1] then 304 | if key == "r" and gameover then 305 | gameFunctions.changeState("game") 306 | end 307 | 308 | return 309 | end 310 | 311 | if key == "a" then 312 | objects["player"][1]:moveleft(true) 313 | elseif key == "d" then 314 | objects["player"][1]:moveright(true) 315 | elseif key == " " then 316 | objects["player"][1]:jump() 317 | end 318 | end 319 | 320 | function game_keyreleased(key) 321 | if not objects["player"][1] then 322 | return 323 | end 324 | 325 | if key == "a" then 326 | objects["player"][1]:moveleft(false) 327 | elseif key == "d" then 328 | objects["player"][1]:moveright(false) 329 | end 330 | end 331 | 332 | function loadMap(map) 333 | loadmap = love.image.newImageData("graphics/" .. map .. ".png") 334 | 335 | objects = {} 336 | 337 | objects["player"] = {} 338 | objects["tile"] = {} 339 | objects["bit"] = {} 340 | objects["bitblood"] = {} 341 | objects["explosion"] = {} 342 | objects["digits"] = {} 343 | objects["proxy"] = {} 344 | objects["firewall"] = {} 345 | 346 | objects["console"] = 347 | { 348 | newConsole("Console initialized. Use A and D to move and SPACE to jump.") 349 | } 350 | 351 | objects["antivirus"] = {} 352 | timers = { ["bits"] = {} , ["console"] = {} , ["av"] = {} , ["events"] = {} , ["firewall"] = {} } 353 | 354 | mapscrollx = 0 355 | mapscrolly = 0 356 | 357 | local values = {"0", "1"} 358 | background = {} 359 | for k = 1, loadmap:getHeight() do 360 | for y = 1, loadmap:getWidth() do 361 | local val = values[love.math.random(#values)] 362 | table.insert(background, {value = val, fade = 255, x = (y - 1) * 16 * scale + (16 / 2) * scale - backgroundFont:getWidth(val) / 2, y = (k - 1) * 16 * scale + (16 / 2) * scale - backgroundFont:getHeight(val) / 2}) 363 | end 364 | end 365 | currentPos = 1 366 | positionTimer = 0.01 367 | 368 | gameBatch:clear() 369 | 370 | local playerX, playerY 371 | for y = 1, loadmap:getHeight() do 372 | for x = 1, loadmap:getWidth() do 373 | local r, g, b = loadmap:getPixel(x - 1, y - 1) 374 | 375 | if r == 0 and g == 0 and b == 0 then 376 | table.insert(objects["tile"], newTile((x - 1) * 16, (y - 1) * 16, 1)) 377 | elseif r == 255 and g == 0 and b == 0 then 378 | playerX, playerY = (x - 1) * 16, (y - 1) * 16 379 | end 380 | end 381 | end 382 | 383 | consoleDelay(8, "Uploading virus.. 100%", {255, 35, 0}, function() table.insert(objects["player"], newPlayer(playerX, playerY, true)) bgm_start:stop() bgm:play() end) 384 | 385 | consoleDelay(14, "Streaming bits/s: 3", {255, 255, 255}, function() 386 | table.insert(timers["bits"], newRepeatTimer(3, function() 387 | if #objects["bit"] < 6 and #objects["proxy"] == 0 then 388 | table.insert(objects["bit"], newBit(love.math.random(3 * 16, 15 * 16), love.math.random(2 * 16, 9 * 16))) 389 | end 390 | end)) 391 | end) 392 | 393 | consoleDelay(18, "Stomp bits to infect the machine and steal data") 394 | end 395 | 396 | function consoleDelay(t, s, c, f) 397 | table.insert(timers["console"], newTimer(t, function() 398 | objects["console"][1] = newConsole(s, c, f) 399 | end)) 400 | end 401 | 402 | function newTimer(t, f, stopAtMax) 403 | local timerthing = {} 404 | 405 | timerthing.maxtime = t 406 | timerthing.func = f 407 | timerthing.time = 0 408 | timerthing.stopAtMax = stopAtMax 409 | 410 | timerthing.stop = false 411 | 412 | function timerthing:update(dt) 413 | if self.time < self.maxtime then 414 | self.time = self.time + dt 415 | else 416 | if not self.stop then 417 | self.func() 418 | self.remove = true 419 | self.stop = true 420 | end 421 | end 422 | end 423 | 424 | return timerthing 425 | end 426 | 427 | function newRepeatTimer(t, f) 428 | local timerthing = {} 429 | 430 | timerthing.maxtime = t 431 | timerthing.func = f 432 | timerthing.time = 0 433 | timerthing.stopAtMax = stopAtMax 434 | 435 | timerthing.stop = false 436 | 437 | function timerthing:update(dt) 438 | if self.time < self.maxtime then 439 | self.time = self.time + dt 440 | else 441 | self.func() 442 | self.time = 0 443 | end 444 | end 445 | 446 | return timerthing 447 | end 448 | 449 | function newBackgroundLine(dir) 450 | local x = love.math.random(4, gameFunctions.getWidth() - 8) 451 | local y = 0 452 | 453 | local r, g, b, a = love.math.random(120, 255), love.math.random(120, 255), love.math.random(120, 255), 100 454 | 455 | local line = {} 456 | 457 | line.x = x 458 | line.y = y 459 | line.initX = x 460 | line.initY = y 461 | 462 | line.speed = love.math.random(80, 160) 463 | 464 | line.width = love.math.random(4, 8) 465 | line.height = love.math.random(30, 40) 466 | 467 | line.colors = {r, g, b, a} 468 | 469 | return line 470 | end -------------------------------------------------------------------------------- /states/title.lua: -------------------------------------------------------------------------------- 1 | function title_init() 2 | introtimer = 0 3 | titleRects = {} 4 | 5 | for k = 1, 20 do 6 | titleRects[k] = newBackgroundLine() 7 | end 8 | 9 | titleThings = 10 | { 11 | {"New user session", function() title_runCMD("game") end}, 12 | {"Toggle fullscreen", function() title_runCMD("fullscreen") end}, 13 | {"View credits", function() title_runCMD("credits") end}, 14 | {"Exit terminal", function() title_runCMD("quit") end} 15 | } 16 | 17 | menui = 1 18 | 19 | titlestringi = 0 20 | titlestringrep = 0 21 | lastrep = 0 22 | 23 | gameTitle = "HAX0R?" 24 | gameName = "HAX0R?" 25 | 26 | cmdtimer = 0 27 | titlecmd = "" 28 | titledrawstring = "" 29 | cmdi = 0 30 | realcmd = "" 31 | 32 | cmdendtimer = 0 33 | runcmdfade = 1 34 | 35 | if mobileMode then 36 | table.remove(titleThings, 2) 37 | end 38 | end 39 | 40 | function replace_char(pos, str, r) 41 | return str:sub(1, pos-1) .. r .. str:sub(pos+1) 42 | end 43 | 44 | function title_update(dt) 45 | if introtimer < 0.6 then 46 | introtimer = introtimer + dt 47 | if introtimer < 1/60 then 48 | blipsnd:play() 49 | end 50 | else 51 | for k, v in pairs(titleRects) do 52 | v:update(dt) 53 | end 54 | 55 | if titlemusic:isStopped() then 56 | titlemusic:play() 57 | end 58 | 59 | if titlestringrep < 10/60 then 60 | titlestringrep = titlestringrep + dt 61 | else 62 | if lastrep ~= 0 then 63 | gameTitle = replace_char(lastrep, gameName, gameName:sub(lastrep, lastrep)) 64 | end 65 | titlestringi = love.math.random(#gameMap) 66 | lastrep = titlestringi 67 | gameTitle = replace_char(lastrep, gameTitle, gameMap[lastrep]) 68 | titlestringrep = 0 69 | end 70 | end 71 | 72 | if #titlecmd > 0 then 73 | if #titledrawstring < #titlecmd then 74 | if cmdtimer < 0.03 then 75 | cmdtimer = cmdtimer + dt 76 | else 77 | cmdi = cmdi + 1 78 | titledrawstring = titledrawstring .. titlecmd:sub(cmdi, cmdi) 79 | cmdtimer = 0 80 | end 81 | else 82 | if realcmd then 83 | cmdendtimer = cmdendtimer + dt 84 | runcmdfade = cmdendtimer%2 85 | 86 | if cmdendtimer > 2 then 87 | if realcmd == "quit" then 88 | love.event.quit() 89 | elseif realcmd == "game" then 90 | gameFunctions.changeState("game") 91 | titlemusic:stop() 92 | elseif realcmd == "fullscreen" then 93 | fullscreen = not fullscreen 94 | gameFunctions.fullScreen() 95 | elseif realcmd == "credits" then 96 | showCredits = true 97 | end 98 | 99 | titledrawstring = "" 100 | titlecmd = "" 101 | realcmd = "" 102 | cmdi = 0 103 | cmdtimer = 0 104 | cmdendtimer = 0 105 | end 106 | end 107 | end 108 | end 109 | end 110 | 111 | function title_draw() 112 | if introtimer < 1/60 then 113 | love.graphics.rectangle("fill", 0, (gameFunctions.getHeight() / 2) * scale - 1 * scale, gameFunctions.getWidth() * scale, 2 * scale) 114 | elseif introtimer > 1/60 and introtimer < 0.1 then 115 | love.graphics.rectangle("fill", 0, 0, gameFunctions.getWidth() * scale, gameFunctions.getHeight() * scale) 116 | elseif introtimer > 0.4 then 117 | for k, v in pairs(titleRects) do 118 | v:draw() 119 | end 120 | 121 | if not showCredits then 122 | love.graphics.setColor(255, 255, 255) 123 | love.graphics.setFont(mainFont) 124 | love.graphics.print(gameTitle, (gameFunctions.getWidth() / 2) * scale - mainFont:getWidth(gameTitle) / 2, 40 * scale) 125 | 126 | love.graphics.setFont(backgroundFont) 127 | 128 | local offset 129 | for k = 1, #titleThings do 130 | if menui == k then 131 | offset = backgroundFont:getWidth("> ") 132 | else 133 | offset = 0 134 | end 135 | love.graphics.print(titleThings[k][1], 1 * scale + offset, (120 + (k - 1) * 14) * scale) 136 | end 137 | 138 | love.graphics.print("> ", 1 * scale, (120 + (menui - 1) * 14) * scale) 139 | 140 | if #titledrawstring > 0 then 141 | love.graphics.print(titledrawstring, 1 * scale, gameFunctions.getHeight() * scale - backgroundFont:getHeight("~$" .. titledrawstring)) 142 | 143 | love.graphics.setColor(255, 255, 255, 255 * runcmdfade) 144 | love.graphics.print("_", 1 * scale + backgroundFont:getWidth(titledrawstring), gameFunctions.getHeight() * scale - backgroundFont:getHeight("_")) 145 | end 146 | end 147 | 148 | if showCredits then 149 | for k = 1, #credits do 150 | love.graphics.print(credits[k], (gameFunctions.getWidth() / 2) * scale - backgroundFont:getWidth(credits[k]) / 2, (12 + (k - 1) * 14) * scale) 151 | end 152 | end 153 | end 154 | end 155 | 156 | function title_keypressed(key) 157 | if key == controls["down"] then 158 | menui = math.min(menui + 1, #titleThings) 159 | end 160 | 161 | if key == controls["up"] then 162 | menui = math.max(menui - 1, 1) 163 | end 164 | 165 | if key == controls["jump"] then 166 | if not showCredits then 167 | titleThings[menui][2]() 168 | else 169 | showCredits = false 170 | end 171 | end 172 | 173 | if key == controls["pause"] then 174 | love.event.quit() 175 | end 176 | end 177 | 178 | function title_runCMD(s) 179 | titlecmd = "~$run " .. s 180 | realcmd = s 181 | end -------------------------------------------------------------------------------- /states/win.lua: -------------------------------------------------------------------------------- 1 | function win_init() 2 | love.graphics.setFont(winFont) 3 | wintexts = {} 4 | 5 | wintimers = 6 | { 7 | newTimer(1, function() addText("Booting local mach-- [WARN] PATH CORRUPT!", {255, 35, 0}) end), 8 | newTimer(4, function() addText("Checking BIOS..", {0, 148, 255}) end), 9 | newTimer(6, function() addText("Checking grub..", {128, 128, 128}) end), 10 | newTimer(8, function() addText("Checking filesystem on user@ludumdare33:/", {255, 106, 0}) end), 11 | newTimer(10, function() addText("Bad sector found on user@ludumdare33:/!", {255, 35, 0}) bgm_start:stop() bgm:stop() end), 12 | newTimer(12, function() addText("Initializing data..") end), 13 | newTimer(14, function() addText("Boot sector 0 at head position 0\nfilesystem is fully corrupt!", {255, 35, 0}, 10) end), 14 | newTimer(16, function() addText('"You cannot get rid of me."\n- H@#0R, your "monster" of a virus', {255, 255, 255}, 30) end), 15 | newTimer(20, function() wintexts = {} end) 16 | } 17 | end 18 | 19 | local virus = " + + \n++\\+++/+\n++@+++@+\n+++++++++\n++++==+++\n+++++++++" 20 | local virusi = 0 21 | local virustimer = 0 22 | local virusdraw = "" 23 | 24 | function win_update(dt) 25 | for k, v in pairs(wintimers) do 26 | v:update(dt) 27 | end 28 | 29 | if #wintexts == 8 then 30 | virustimer = virustimer + dt 31 | if virustimer > 0.03 then 32 | virusi = virusi + 1 33 | virusdraw = virusdraw .. virus:sub(virusi, virusi) 34 | virustimer = 0 35 | end 36 | end 37 | end 38 | 39 | function win_draw() 40 | for k = 1, #wintexts do 41 | love.graphics.setColor(wintexts[k].color) 42 | love.graphics.print(wintexts[k].text, 1 * scale, (wintexts[k].offset * scale) + 1 * scale + (k - 1) * 10 * scale) 43 | end 44 | 45 | love.graphics.print(virusdraw, 1 * scale, 130 * scale) 46 | 47 | if #virusdraw == #virus and #wintexts == 0 then 48 | for k = 1, #credits do 49 | love.graphics.print(credits[k], (gameFunctions.getWidth() / 2) * scale - winFont:getWidth(credits[k]) / 2, (10 + (k - 1) * 10) * scale) 50 | end 51 | end 52 | end 53 | 54 | function addText(t, color, offset) 55 | local c = color or {255, 255, 255} 56 | local off = offset or 0 57 | table.insert(wintexts, {text = t, color = c, offset = off}) 58 | end 59 | 60 | credits = 61 | { 62 | "CREDITS :: HAX0R?", 63 | "", 64 | "A GAME MADE FOR LUDUM DARE #33", 65 | "", 66 | "Game and code by Jeremy S. Postelnek", 67 | "Music made with PixiTracker", 68 | "Art made with Paint.NET", 69 | "Sounds made with BFXR", 70 | "Font used is Windows CMD", 71 | "", 72 | "Check out my blog for other games:", 73 | "http://www.jpostelnek.blogspot.com/" 74 | } -------------------------------------------------------------------------------- /tile.lua: -------------------------------------------------------------------------------- 1 | function newTile(x, y, id) 2 | local tile = {} 3 | 4 | tile.x = x 5 | tile.y = y 6 | 7 | tile.width = 16 8 | tile.height = 16 9 | 10 | tile.speedx = 0 11 | tile.speedy = 0 12 | 13 | gameBatch:add(floorQuads[id], x * scale, y * scale, 0, scale, scale) 14 | 15 | tile.passive = false 16 | 17 | return tile 18 | end -------------------------------------------------------------------------------- /win.lua: -------------------------------------------------------------------------------- 1 | function win_init() 2 | love.graphics.setFont(winFont) 3 | wintexts = {} 4 | 5 | wintimers = 6 | { 7 | newTimer(1, function() addText("Booting local mach-- [WARN] PATH CORRUPT!", {255, 35, 0}) end), 8 | newTimer(4, function() addText("Checking BIOS..", {0, 148, 255}) end), 9 | newTimer(6, function() addText("Checking grub..", {128, 128, 128}) end), 10 | newTimer(8, function() addText("Checking filesystem on user@ludumdare33:/", {255, 106, 0}) end), 11 | newTimer(10, function() addText("Bad sector found on user@ludumdare33:/!", {255, 35, 0}) bgm_start:stop() bgm:stop() end), 12 | newTimer(12, function() addText("Initializing data..") end), 13 | newTimer(14, function() addText("Boot sector 0 at head position 0\nfilesystem is fully corrupt!", {255, 35, 0}, 10) end), 14 | newTimer(16, function() addText('"You cannot get rid of me."\n- H@#0R, your "monster" of a virus', {255, 255, 255}, 30) end), 15 | newTimer(20, function() wintexts = {} end) 16 | } 17 | end 18 | 19 | local virus = " + + \n++\\+++/+\n++@+++@+\n+++++++++\n++++==+++\n+++++++++" 20 | local virusi = 0 21 | local virustimer = 0 22 | local virusdraw = "" 23 | 24 | function win_update(dt) 25 | for k, v in pairs(wintimers) do 26 | v:update(dt) 27 | end 28 | 29 | if #wintexts == 8 then 30 | virustimer = virustimer + dt 31 | if virustimer > 0.03 then 32 | virusi = virusi + 1 33 | virusdraw = virusdraw .. virus:sub(virusi, virusi) 34 | virustimer = 0 35 | end 36 | end 37 | end 38 | 39 | function win_draw() 40 | for k = 1, #wintexts do 41 | love.graphics.setColor(wintexts[k].color) 42 | love.graphics.print(wintexts[k].text, 1 * scale, (wintexts[k].offset * scale) + 1 * scale + (k - 1) * 10 * scale) 43 | end 44 | 45 | love.graphics.print(virusdraw, 1 * scale, 130 * scale) 46 | 47 | if #virusdraw == #virus and #wintexts == 0 then 48 | for k = 1, #credits do 49 | love.graphics.print(credits[k], (gameFunctions.getWidth() / 2) * scale - winFont:getWidth(credits[k]) / 2, (10 + (k - 1) * 10) * scale) 50 | end 51 | end 52 | end 53 | 54 | function addText(t, color, offset) 55 | local c = color or {255, 255, 255} 56 | local off = offset or 0 57 | table.insert(wintexts, {text = t, color = c, offset = off}) 58 | end 59 | 60 | credits = 61 | { 62 | "CREDITS :: HAX0R?", 63 | "", 64 | "A GAME MADE FOR LUDUM DARE #33", 65 | "", 66 | "Game and code by Jeremy S. Postelnek", 67 | "Music made with PixiTracker", 68 | "Art made with Paint.NET", 69 | "Sounds made with BFXR", 70 | "Font used is Windows CMD", 71 | "", 72 | "Check out my blog for other games:", 73 | "http://www.jpostelnek.blogspot.com/" 74 | } --------------------------------------------------------------------------------