if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE")=="1" then LLDEBUGGER=require('lldebugger') LLDEBUGGER.start() end require 'funcs' DEBUG_showKey = false PENTO_MODE = false SAVE_DIR = 'saves/' REPLAY_DIR = 'saves/replays/' if not love.filesystem.getInfo(REPLAY_DIR) then love.filesystem.createDirectory(REPLAY_DIR) end CONFIG_FILE = 'config.sav' HIscoreFILE = 'hiscores.sav' CURRENT_OS = love.system.getOS() MOBILE = CURRENT_OS == "Android" or CURRENT_OS == "iOS" LOADING_IMAGE_FILE = love.graphics.newImage('res/loading.png') --- Show the loading text while we are loading resources
--- **WARNING**: should only be used while loading the game! function ShowLoadingText(thing) love.resize(love.graphics.getDimensions()) love.graphics.replaceTransform(GLOBAL_TRANSFORM) love.graphics.setFont(love.graphics.newFont(20)) love.graphics.clear() love.graphics.draw(LOADING_IMAGE_FILE,0,0,0,0.5) drawText("Loading ".. thing .. "...", 15, 455, 1e99, "left") love.graphics.flushBatch() love.graphics.present() end function love.load() math.randomseed(os.time()) require "modules.file" "binser" require "settings" -- Window stuffs love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true}); love.window.setFullscreen(SETTINGS["fullscreen"]) -- Make a new transformer GLOBAL_TRANSFORM = love.math.newTransform() love.resize(love.graphics.getWidth(), love.graphics.getHeight()) -- Now it's real time to load all stuffs! require "load" -- Most game's resources are loaded in here require "modules.scene" require "game.vctrl" -- VCTRL function SCENE.update() SCENE.update = function() end SCENE = SETTINGS.firstTime and InputConfigScene(true) or TitleScene() end function SCENE.render() SCENE.render = function() end love.graphics.draw(LOADING_IMAGE_FILE,0,0,0,0.5) end -- VCTRL.toggle(love.system.getOS()=='Android' or true) -- VCTRL.new{ -- up down left right --- right left down up -- -- {type='button',x= 100,y=320,key= 'up',r=35,iconSize=60,alpha=0.75}, -- -- {type='button',x= 100,y=440,key= 'down',r=35,iconSize=60,alpha=0.75}, -- -- {type='button',x= 40,y=380,key= 'left',r=35,iconSize=60,alpha=0.75}, -- -- {type='button',x= 160,y=380,key= 'right',r=35,iconSize=60,alpha=0.75}, -- -- {type='button',x=640- 40,y=380,key= 'rotate_left',r=35,iconSize=60,alpha=0.75}, -- -- {type='button',x=640-160,y=380,key= 'rotate_left2',r=35,iconSize=60,alpha=0.75}, -- -- {type='button',x=640-100,y=440,key= 'rotate_right',r=35,iconSize=60,alpha=0.75}, -- -- {type='button',x=640-100,y=320,key='rotate_right2',r=35,iconSize=60,alpha=0.75}, -- } VCTRL.new(SETTINGS.input.virtual) end function love.resize(w, h) SCREEN_SCALE_FACTOR = math.min(w / 640, h / 480) GLOBAL_TRANSFORM:setTransformation( (w - SCREEN_SCALE_FACTOR * 640) / 2, (h - SCREEN_SCALE_FACTOR * 480) / 2, 0, SCREEN_SCALE_FACTOR ) end function love.draw() love.graphics.replaceTransform(GLOBAL_TRANSFORM) love.graphics.clear() love.graphics.push() SCENE:render() -- -- Grid system -- local grid_width, grid_height = 40, 20 -- love.graphics.setColor(1,1,1,0.5) -- love.graphics.setLineWidth(1) -- -- From 0 to X -- for ix=0,math.floor(640 / grid_width) do -- love.graphics.line(grid_width * ix, 0 , grid_width * ix, 480) -- end -- -- From 0 to Y -- for iy=0,math.floor(480 / grid_height) do -- love.graphics.line(0, grid_height * iy, 640, grid_height * iy) -- end -- local x, y = GLOBAL_TRANSFORM:inverseTransformPoint(love.mouse.getPosition()) -- love.graphics.setColor(0, 0, 0, 0.8) -- love.graphics.rectangle("fill", 5, 450, 115, 25) -- drawText(string.format("X: %.1d; Y: %.1d", x, y), 10, 455, 110, "left") -- love.graphics.setColor(1, 1, 1, 1) -- love.graphics.setLineWidth(2) -- love.graphics.rectangle("line", 0, 0, 640, 480) love.graphics.pop() end function love.mousepressed(x, y, b, isTouch, presses) if isTouch then return end local x,y=GLOBAL_TRANSFORM:inverseTransformPoint(x,y) SCENE:onInputPress{type = "mouse", x = x, y = y, presses = presses} end function love.mousereleased(x, y, b, isTouch, presses) if isTouch then return end local x,y=GLOBAL_TRANSFORM:inverseTransformPoint(x,y) SCENE:onInputRelease{type = "mouse", x = x, y = y, presses = presses} end function love.mousemoved(x, y, dx, dy, isTouch) if isTouch then return end local x,y=GLOBAL_TRANSFORM:inverseTransformPoint(x,y) local dx,dy=dx/SCREEN_SCALE_FACTOR,dy/SCREEN_SCALE_FACTOR SCENE:onInputMove{type = "mouse", x = x, y = y, dx = dx, dy = dy} end function love.wheelmoved(dx, dy) SCENE:onInputMove{type = "wheel", dx = dx, dy = dy} end function love.touchpressed(id,x,y) local x,y=GLOBAL_TRANSFORM:inverseTransformPoint(x,y) SCENE:onInputPress{type = "touch", x = x, y = y, dx = 0, dy = 0, id = id} end function love.touchmoved(id,x,y,dx,dy) local x,y=GLOBAL_TRANSFORM:inverseTransformPoint(x,y) SCENE:onInputMove{type = "touch", x = x, y = y, dx = dx, dy = dy, id = id} end function love.touchreleased(id,x,y) local x,y=GLOBAL_TRANSFORM:inverseTransformPoint(x,y) SCENE:onInputRelease{type = "touch", x = x, y = y, dx = 0, dy = 0, id = id} end function love.keypressed(key, scancode) local input_pressed=nil -- global hotkeys if scancode == "f4" then SETTINGS["fullscreen"] = not SETTINGS["fullscreen"] love.window.setFullscreen(SETTINGS["fullscreen"]) elseif scancode == "f2" and SCENE.title ~= "Input Config" and SCENE.title ~= "Game" then SCENE = InputConfigScene() elseif scancode == "f12" then LLDEBUGGER.requestBreak() -- elseif scancode == "f11" then SETTINGS.firstTime = true -- function keys are reserved elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f1[0-2]+$") then return -- escape is reserved for menu_back elseif scancode == "escape" then SCENE:onInputPress{input="menu_back", type="key", key=key, scancode=scancode} -- pass any other key to the scene, with its configured mapping else if SETTINGS.input and SETTINGS.input.keys then input_pressed = SETTINGS.input.keys[scancode] end SCENE:onInputPress{input=input_pressed, type="key", key=key, scancode=scancode} end end function love.keyreleased(key, scancode) local input_released = nil -- escape is reserved for menu_back if scancode == "escape" or scancode == 'acback' then SCENE:onInputRelease{input="menu_back", type="key", key=key, scancode=scancode} -- function keys are reserved elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f1[0-2]+$") then return -- handle all other keys; tab is reserved, but the input config scene keeps it from getting configured as a game input, so pass tab to the scene here else if SETTINGS.input and SETTINGS.input.keys then input_released = SETTINGS.input.keys[scancode] end SCENE:onInputRelease{input=input_released, type="key", key=key, scancode=scancode} end end function love.joystickpressed(joystick, button) local input_pressed = nil if SETTINGS.input and SETTINGS.input.joysticks and SETTINGS.input.joysticks[joystick:getName()] and SETTINGS.input.joysticks[joystick:getName()].buttons then input_pressed = SETTINGS.input.joysticks[joystick:getName()].buttons[button] end SCENE:onInputPress({input=input_pressed, type="joybutton", name=joystick:getName(), button=button}) end function love.joystickreleased(joystick, button) local input_released = nil if SETTINGS.input and SETTINGS.input.joysticks and SETTINGS.input.joysticks[joystick:getName()] and SETTINGS.input.joysticks[joystick:getName()].buttons then input_released = SETTINGS.input.joysticks[joystick:getName()].buttons[button] end SCENE:onInputRelease({input=input_released, type="joybutton", name=joystick:getName(), button=button}) end function love.joystickaxis(joystick, axis, value) local input_pressed = nil local positive_released = nil local negative_released = nil if SETTINGS.input and SETTINGS.input.joysticks and SETTINGS.input.joysticks[joystick:getName()] and SETTINGS.input.joysticks[joystick:getName()].axes and SETTINGS.input.joysticks[joystick:getName()].axes[axis] then if math.abs(value) >= 1 then input_pressed = SETTINGS.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"] end positive_released = SETTINGS.input.joysticks[joystick:getName()].axes[axis].positive negative_released = SETTINGS.input.joysticks[joystick:getName()].axes[axis].negative end if math.abs(value) >= 1 then SCENE:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) else SCENE:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) SCENE:onInputRelease({input=negative_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value}) end end local last_hat_direction = "" local directions = { ["u"] = "up", ["d"] = "down", ["l"] = "left", ["r"] = "right", } function love.joystickhat(joystick, hat, direction) local input_pressed = nil local has_hat = false if SETTINGS.input and SETTINGS.input.joysticks and SETTINGS.input.joysticks[joystick:getName()] and SETTINGS.input.joysticks[joystick:getName()].hats and SETTINGS.input.joysticks[joystick:getName()].hats[hat] then if direction ~= "c" then input_pressed = SETTINGS.input.joysticks[joystick:getName()].hats[hat][direction] end has_hat = true end if input_pressed then for i = 1, #direction do local char = direction:sub(i, i) local _, count = last_hat_direction:gsub(char, char) if count == 0 then SCENE:onInputPress({input=SETTINGS.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) end end for i = 1, #last_hat_direction do local char = last_hat_direction:sub(i, i) local _, count = direction:gsub(char, char) if count == 0 then SCENE:onInputRelease({input=SETTINGS.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) end end last_hat_direction = direction elseif has_hat then for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do SCENE:onInputRelease({input=SETTINGS.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) end last_hat_direction = "" elseif direction ~= "c" then for i = 1, #direction do local char = direction:sub(i, i) local _, count = last_hat_direction:gsub(char, char) if count == 0 then SCENE:onInputPress({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) end end for i = 1, #last_hat_direction do local char = last_hat_direction:sub(i, i) local _, count = direction:gsub(char, char) if count == 0 then SCENE:onInputRelease({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char}) end end last_hat_direction = direction else for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do SCENE:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction}) end last_hat_direction = "" end end function love.focus(f) end local TARGET_FPS = 60 function love.run() if love.load then love.load(love.arg.parseGameArguments(arg), arg) end if love.timer then love.timer.step() end local dt = 0 local last_time = love.timer.getTime() local time_accumulator = 0 return function() if love.event then love.event.pump() for name, a,b,c,d,e,f in love.event.poll() do if name == "quit" then if not love.quit or not love.quit() then return a or 0 end end love.handlers[name](a,b,c,d,e,f) end end if SCENE and SCENE.update and love.timer then SCENE:update() local frame_duration = 1.0 / TARGET_FPS if time_accumulator < frame_duration then if love.graphics and love.graphics.isActive() and love.draw then love.graphics.origin() love.graphics.clear(love.graphics.getBackgroundColor()) love.draw() love.graphics.present() end local end_time = last_time + frame_duration local time = love.timer.getTime() while time < end_time do love.timer.sleep(0.001) time = love.timer.getTime() end time_accumulator = time_accumulator + time - last_time end time_accumulator = time_accumulator - frame_duration end last_time = love.timer.getTime() end end function love.errorhandler(msg) local msg = msg or "I don't know if mycophobia's real name is \"mycophobiatrophilusiania\" or not.\nBUT WHO ATE THE ERROR MESSAGE?! DTET_ENJOYER, DID YOU?\n" local showScreenshot = false local errorCopied = false local enter_fullscreen = SETTINGS and SETTINGS["fullscreen"] or false -- Handling the error local err={"Error:"..msg} local c=2 for l in debug.traceback("",2):gmatch("(.-)\n") do if c>2 then if not l:find("boot") then err[c]=l:gsub("^\t*","\t") c=c+1 end else err[2]="Traceback" c=3 end end print("\n"..table.concat(err,"\n",1,c-2)) local tracebacks = table.concat(err,"\n", 4) if drawText == nil then pcall(function() FONT_tromi = love.graphics.newFont('res/fonts/monofonto rg.otf', 20) require "funcs" end) if drawText == nil then love.window.setMode(640, 480, {resizable = true}) return function() -- If "funcs" failed to load, we can only return a more simple version of error screen love.event.pump() for e, a, b, c in love.event.poll() do if e == "quit" then return 1 end end love.graphics.origin() love.graphics.clear() love.graphics.setColor(1, 1, 1) love.graphics.setFont(FONT_tromi) love.graphics.printf( err[1]:sub(7).."\nTraceback:\n"..tracebacks, 30, 30, love.graphics.getWidth() - 10, "left" ) love.graphics.present() if love.timer then love.timer.sleep(0.1) end end end end -- Try to create a canva love.graphics.origin() local screenshot_canva, screenshot_canva_scale local ok, _ = pcall(function() if love.graphics.getSystemLimits().texturesize >= 1280 then screenshot_canva = love.graphics.newCanvas(1280, 960) screenshot_canva_scale = 0.5 else error() end end) if not ok then screenshot_canva = love.graphics.newCanvas(640, 480) screenshot_canva_scale = 1 end -- Then draw everything again love.graphics.setCanvas(screenshot_canva) pcall( function() love.graphics.origin() local transformer = love.math.newTransform(0, 0, 0, 2, 2) love.graphics.replaceTransform(transformer) SCENE:render() end ) love.audio.stop() love.graphics.setCanvas() local function draw() love.graphics.origin() love.graphics.replaceTransform(GLOBAL_TRANSFORM) love.graphics.clear() love.graphics.setColor(1, 1, 1) love.graphics.draw(screenshot_canva, 0, 0, 0, screenshot_canva_scale) if not showScreenshot then love.graphics.setColor(0, 0, 0, 0.75) love.graphics.rectangle("fill", 0, 0, 640, 480) drawText([[ OH NO! Tromi has crashed. Since this is not the official port, please do not report any bugs to mycophobia. Instead, report this to me via my Discord ``sweetsea'' with a screenshot of this. REMEMBER TO SCREENSHOT ERROR INFO BEFORE QUITTING BECAUSE THEY ARE NOT SAVED! Ctrl + C: copy the error info | If you click / tap, a window appears with 4 options: Space : show/hide screenshot | OK : Quit Copy: copy error info Escape : Quit | Cancel: Go back Show: show/hide screenshot ]], 20, 10, 620, "left") drawText(err[1]:sub(7).."\nTraceback:"..(errorCopied and " (Copied to clipboard)\n" or "\n")..tracebacks, 20, 180, 620, "left") else love.graphics.setColor(0, 0, 0, 0.8) love.graphics.rectangle("fill", 15, 450, 400, 25, 5, 5) drawText("Tromi has crashed! Press Space or tap to show error info", 15, 455, 400, "left") end love.graphics.present() end local fullErrorText = tracebacks local function copyToClipboard() love.system.setClipboardText(fullErrorText) errorCopied = true end local buttons = {"OK", "Cancel", "Copy", "Show"} return function() love.event.pump() for e, a, b, c in love.event.poll() do if e == "quit" then return 1 elseif e == "keypressed" and a == "escape" then return 1 elseif e == "keypressed" and a == "c" and love.keyboard.isDown("lctrl", "rctrl") then copyToClipboard() elseif e == "keypressed" and a == "space" then showScreenshot = not showScreenshot elseif e == "keypressed" and a == "f4" then enter_fullscreen = not enter_fullscreen love.window.setFullscreen(enter_fullscreen) elseif e == "mousepressed" then local pressed = love.window.showMessageBox("Quit? Screenshot? Copy?", "Remember to screenshot error info before quitting because they are not saved!", buttons) if pressed == 1 then return 1 elseif pressed == 3 then copyToClipboard() elseif pressed == 4 then showScreenshot = not showScreenshot end elseif e == "resize" then love.resize(love.graphics.getDimensions()) end end draw() if love.timer then love.timer.sleep(0.1) end end end local minos = {'R_d', 'O_d', 'Y_d', 'G_d', 'C_d', 'B_d', 'M_d'} local main_bg_grid = {} for x=1, 40 do main_bg_grid[x] = {} for y=1, 30 do main_bg_grid[x][y] = 0 end end local main_bg_cur_pos = {20,6} local main_bg_cur_color = minos[love.math.random(1,7)] local main_bg_cur_mino = 1 local main_bg_draw_frame = 0 local main_bg_last_color = nil function MainBackground() if SETTINGS["music"] and not SOUNDS["bgm_title"]:isPlaying() then SOUNDS["bgm_title"]:setVolume(0.3) SOUNDS["bgm_title"]:play() end local y = 40 if main_bg_draw_frame >= 16 then while y > 1 do for x = 1, 40 do main_bg_grid[x][y] = main_bg_grid[x][y-1] end y = y - 1 end for x=1, 40 do main_bg_grid[x][1] = 0 end main_bg_draw_frame = 0 main_bg_cur_pos[2] = main_bg_cur_pos[2] + 1 end local directions = { {0,-1},{1,0}, {-1,0}} local test_dir = directions[love.math.random(1,3)] main_bg_cur_pos[1] = main_bg_cur_pos[1] + test_dir[1] main_bg_cur_pos[2] = main_bg_cur_pos[2] + test_dir[2] if main_bg_cur_pos[1] > 40 then main_bg_cur_pos[1] = 40 end if main_bg_cur_pos[1] < 1 then main_bg_cur_pos[1] = 1 end if main_bg_cur_pos[2] > 30 then main_bg_cur_pos[2] = 30 end if main_bg_cur_pos[2] < 1 then main_bg_cur_pos[2] = 1 end if main_bg_grid[main_bg_cur_pos[1]][main_bg_cur_pos[2]] == 0 then main_bg_grid[main_bg_cur_pos[1]][main_bg_cur_pos[2]] = main_bg_cur_color main_bg_cur_mino = main_bg_cur_mino + 1 end for x=1,40 do for y=1,30 do if main_bg_grid[x][y] ~= 0 then love.graphics.setColor(1, 1, 1, 0.4) if ((x-1)*48)-560 > 0 and ((x-1)*48)-560 < 640 then love.graphics.draw(BLOCKS["2tie"][main_bg_grid[x][y]], ((x-1)*48)-570, (((y+2)*48)+main_bg_draw_frame*3)-480,0, 3) end love.graphics.setColor(1, 1, 1, 1) end end end for x=1,40 do for y=1,30 do if main_bg_grid[x][y] ~= 0 then love.graphics.setColor(1, 1, 1, 1) love.graphics.draw(BLOCKS["2tie"][main_bg_grid[x][y]], (x-1)*16, ((y-1)*16)+main_bg_draw_frame) end end end for x=1,40 do for y=1,30 do if main_bg_grid[x][y] ~= 0 then love.graphics.setColor(1, 1, 1, 0.6) if ((x-1)*32)-320 > 0 and ((x-1)*32)-320 < 640 then love.graphics.draw(BLOCKS["2tie"][main_bg_grid[x][y]], ((x-1)*32)-320, (((y+1)*32)+main_bg_draw_frame*2)-320,0, 2) end love.graphics.setColor(1, 1, 1, 1) end end end if main_bg_cur_mino == 5 then --if main_bg_cur_pos[2] < 4 then -- main_bg_cur_pos[2] = 4 -- main_bg_cur_pos[1] = love.math.random(4, 36) --end main_bg_cur_pos = {love.math.random(16,24),6} main_bg_last_color = main_bg_cur_color while main_bg_cur_color == main_bg_last_color do main_bg_cur_color = minos[love.math.random(1,7)] end main_bg_cur_mino = 1 end main_bg_placed = false main_bg_draw_frame = main_bg_draw_frame + 1 end