From 0dce23b4b24ae74889550dc0b81ea393c047f929 Mon Sep 17 00:00:00 2001 From: cursed22bc Date: Tue, 10 Mar 2026 23:16:58 +0200 Subject: evil window hacks --- main.lua | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 203 insertions(+), 13 deletions(-) (limited to 'main.lua') diff --git a/main.lua b/main.lua index 0d66c98..608d82a 100644 --- a/main.lua +++ b/main.lua @@ -1,7 +1,7 @@ local VIRTUAL_WIDTH, VIRTUAL_HEIGHT = 16*10*5, 9*10*5 local CANVAS_PADDING = 6 -DEBUG = false +DEBUG = true local CANVAS_WIDTH = VIRTUAL_WIDTH + CANVAS_PADDING local CANVAS_HEIGHT = VIRTUAL_HEIGHT + CANVAS_PADDING @@ -13,6 +13,10 @@ local offsetX, offsetY = 0, 0 local dpiScale = 1 local canvas = nil local smoothCameraShader = nil +local menuBgShader = nil +local liquidShader = nil +local menuCanvas = nil +local menuTime = 0 local shaderEnabled = true local cameraModule = require("camera") @@ -22,7 +26,7 @@ local HUD = require("hud") local hud = nil local previousState = nil -local currentState = "game" +local currentState = "menu" local currentMapPath = "assets/maps/tilemap.lua" local currentTilesets = { tileset = { path = "assets/maps/tileset.png", tilewidth = 16, tileheight = 16 }, @@ -30,6 +34,15 @@ local currentTilesets = { } local world = nil +local menuItems = {} +local menuHover = nil + +local gameFinishPhase = nil +local gameFinishTimer = 0 +local irisRadius = 0 +local IRIS_CLOSE_DURATION = 1.5 +local TEXT_DISPLAY_DURATION = 5.0 + local states = { game = {}, menu = {}, @@ -39,41 +52,185 @@ local states = { local function recalcScale(w, h) dpiScale = (love.window.getDPIScale and love.window.getDPIScale()) or 1 - scale = math.max(1, math.floor(math.min(w / VIRTUAL_WIDTH, h / VIRTUAL_HEIGHT) / dpiScale)) + scale = math.max(1, math.min(w / VIRTUAL_WIDTH, h / VIRTUAL_HEIGHT) / dpiScale) finalScale = scale * dpiScale offsetX = math.floor((w - VIRTUAL_WIDTH * finalScale) / 2) offsetY = math.floor((h - VIRTUAL_HEIGHT * finalScale) / 2) end +local function screenToCanvas(sx, sy) + local drawX = offsetX - (CANVAS_PADDING * finalScale) / 2 + local drawY = offsetY - (CANVAS_PADDING * finalScale) / 2 + return (sx - drawX) / finalScale, (sy - drawY) / finalScale +end + +local function buildMenuItems() + local btnW, btnH = 120, 32 + local centerX = CANVAS_WIDTH / 2 + local centerY = CANVAS_HEIGHT / 2 + local spacing = 12 + local totalH = 2 * btnH + spacing + local startY = centerY - totalH / 2 + 20 + menuItems = { + { label = "Play", x = centerX - btnW / 2, y = startY, w = btnW, h = btnH, action = "play" }, + { label = "Exit", x = centerX - btnW / 2, y = startY + btnH + spacing, w = btnW, h = btnH, action = "exit" }, + } +end + function states.game.load() local World = require("world") world = World:new() world:load(currentMapPath, currentTilesets) local target = world:getPlayer() or { x = 0, y = 0, width = 16, height = 16 } - camera = cameraModule:new(target, VIRTUAL_WIDTH/2, VIRTUAL_HEIGHT/2, true, WORLD_TO_CANVAS) + camera = cameraModule:new(target, VIRTUAL_WIDTH / 2, VIRTUAL_HEIGHT / 2, true, WORLD_TO_CANVAS) world:setCamera(camera) hud = HUD:new() + gameFinishPhase = nil + gameFinishTimer = 0 + irisRadius = 0 end function states.game.update(dt) - if world then world:update(dt) end + if not world then return end + + if not gameFinishPhase then + world:update(dt) + if world.doorOpened then + gameFinishPhase = "iris" + gameFinishTimer = 0 + irisRadius = math.sqrt((CANVAS_WIDTH / 2) ^ 2 + (CANVAS_HEIGHT / 2) ^ 2) + end + elseif gameFinishPhase == "iris" then + world:update(dt) + gameFinishTimer = gameFinishTimer + dt + local maxR = math.sqrt((CANVAS_WIDTH / 2) ^ 2 + (CANVAS_HEIGHT / 2) ^ 2) + local progress = math.min(gameFinishTimer / IRIS_CLOSE_DURATION, 1) + local eased = 1 - (1 - progress) ^ 2 + irisRadius = maxR * (1 - eased) + if progress >= 1 then + gameFinishPhase = "text" + gameFinishTimer = 0 + irisRadius = 0 + end + elseif gameFinishPhase == "text" then + gameFinishTimer = gameFinishTimer + dt + if gameFinishTimer >= TEXT_DISPLAY_DURATION then + gameFinishPhase = nil + gameFinishTimer = 0 + currentState = "menu" + states.menu.load() + end + end end function states.game.draw() - if camera then camera:set() end - if world then world:draw() end - if camera then camera:unset() end + if gameFinishPhase ~= "text" then + if camera then camera:set() end + if world then world:draw() end + if camera then camera:unset() end + end + + if gameFinishPhase == "iris" then + local cx = CANVAS_WIDTH / 2 + local cy = CANVAS_HEIGHT / 2 + local outerR = math.sqrt(cx * cx + cy * cy) + 10 + local innerR = math.max(irisRadius, 0) + local segments = 64 + local verts = {} + for i = 0, segments do + local angle = (i / segments) * math.pi * 2 + local cs, sn = math.cos(angle), math.sin(angle) + verts[#verts + 1] = { cx + cs * innerR, cy + sn * innerR, 0, 0, 0, 0, 0, 1 } + verts[#verts + 1] = { cx + cs * outerR, cy + sn * outerR, 0, 0, 0, 0, 0, 1 } + end + local mesh = love.graphics.newMesh(verts, "strip", "stream") + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(mesh) + elseif gameFinishPhase == "text" then + love.graphics.setColor(0, 0, 0, 1) + love.graphics.rectangle("fill", 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT) + local font = fonts.get(14) + love.graphics.setFont(font) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.printf("The Frog Escaped the Evil Aquarium", 0, CANVAS_HEIGHT / 2 - font:getHeight() / 2, CANVAS_WIDTH, "center") + love.graphics.setFont(fonts.default) + end end function states.menu.load() camera = nil world = nil + hud = nil + gameFinishPhase = nil + gameFinishTimer = 0 + irisRadius = 0 + menuTime = 0 + love.mouse.setVisible(true) + menuHover = nil end -function states.menu.update(dt) end +function states.menu.update(dt) + menuTime = menuTime + dt + local mx, my = love.mouse.getPosition() + local cx, cy = screenToCanvas(mx, my) + menuHover = nil + for _, btn in ipairs(menuItems) do + if cx >= btn.x and cx <= btn.x + btn.w and cy >= btn.y and cy <= btn.y + btn.h then + menuHover = btn.action + break + end + end +end function states.menu.draw() - love.graphics.print("Menu (state machine ready)", 10, 10) + local prevCanvas = love.graphics.getCanvas() + + love.graphics.setCanvas(menuCanvas) + love.graphics.clear() + if menuBgShader then + love.graphics.setShader(menuBgShader) + end + love.graphics.setColor(1, 1, 1, 1) + love.graphics.rectangle("fill", 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT) + love.graphics.setShader() + love.graphics.setCanvas(prevCanvas) + + if liquidShader then + liquidShader:send("scene", menuCanvas) + liquidShader:send("time", menuTime) + liquidShader:send("resolution", { CANVAS_WIDTH, CANVAS_HEIGHT }) + liquidShader:send("splashCenter", { -10.0, -10.0 }) + liquidShader:send("splashTime", 0.0) + love.graphics.setShader(liquidShader) + end + love.graphics.setColor(1, 1, 1, 1) + love.graphics.draw(menuCanvas, 0, 0) + love.graphics.setShader() + + local titleFont = fonts.get(20) + love.graphics.setFont(titleFont) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.printf("The Frog Escapes Evil Aquarium", 0, CANVAS_HEIGHT / 2 - 80, CANVAS_WIDTH, "center") + + local btnFont = fonts.get(20) + love.graphics.setFont(btnFont) + for _, btn in ipairs(menuItems) do + local hover = menuHover == btn.action + + if hover then + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setLineWidth(1) + love.graphics.rectangle("line", btn.x, btn.y, btn.w, btn.h) + end + + love.graphics.setColor(1, 1, 1, 1) + local tw = btnFont:getWidth(btn.label) + local th = btnFont:getHeight() + love.graphics.print(btn.label, btn.x + btn.w / 2 - tw / 2, btn.y + btn.h / 2 - th / 2) + end + + love.graphics.setFont(fonts.default) + love.graphics.setColor(1, 1, 1, 1) end function states.settings.load() @@ -103,7 +260,7 @@ end function love.load() love.graphics.setDefaultFilter("nearest", "nearest") - love.window.setTitle("Openformer") + love.window.setTitle("The Frog Escapes Evil Aquarium") fonts.load() love.graphics.setFont(fonts.default) @@ -116,10 +273,20 @@ function love.load() print("Warning: smooth_camera.glsl not loaded, using fallback (no sub-pixel offset)") end + local ok2, shader2 = pcall(love.graphics.newShader, "shaders/missing_texture.glsl") + menuBgShader = ok2 and shader2 or nil + + local ok3, shader3 = pcall(love.graphics.newShader, "shaders/liquid.glsl") + liquidShader = ok3 and shader3 or nil + + menuCanvas = love.graphics.newCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) + menuCanvas:setFilter("nearest", "nearest") + local w, h = love.graphics.getWidth(), love.graphics.getHeight() recalcScale(w, h) + buildMenuItems() - love.mouse.setVisible(false) + love.mouse.setVisible(true) local state = states[currentState] if state and state.load then state.load() end @@ -130,6 +297,9 @@ function love.resize(w, h) if canvas then canvas:release() end canvas = love.graphics.newCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) canvas:setFilter("nearest", "nearest") + if menuCanvas then menuCanvas:release() end + menuCanvas = love.graphics.newCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) + menuCanvas:setFilter("nearest", "nearest") end function love.update(dt) @@ -144,6 +314,12 @@ function love.keypressed(key, scancode, isrepeat) if key == "f1" and DEBUG then shaderEnabled = not shaderEnabled end + if key == "escape" and not isrepeat then + if currentState == "game" or currentState == "hud" then + currentState = "menu" + states.menu.load() + end + end if key == "tab" and not isrepeat then if currentState == "game" then previousState = currentState @@ -164,7 +340,21 @@ function love.keypressed(key, scancode, isrepeat) end function love.mousepressed(x, y, button) - if currentState == "hud" and hud then + if currentState == "menu" and button == 1 then + local cx, cy = screenToCanvas(x, y) + for _, btn in ipairs(menuItems) do + if cx >= btn.x and cx <= btn.x + btn.w and cy >= btn.y and cy <= btn.y + btn.h then + if btn.action == "play" then + currentState = "game" + states.game.load() + love.mouse.setVisible(false) + elseif btn.action == "exit" then + love.event.quit() + end + break + end + end + elseif currentState == "hud" and hud then hud:mousepressed(x, y, button) end end -- cgit v1.2.3