V1 update (#1)

This commit is contained in:
Nguyễn Quốc Hưng
2024-06-06 16:01:24 +07:00
committed by Squishy (C6H12O6+NaCl+H2O)
parent 3343d8711b
commit 1d6643448e
30 changed files with 1000 additions and 228 deletions

View File

@@ -35,28 +35,35 @@ Ported to Android (mobile and TV) by SweetSea with on-screen control (with some
### Launch
Navigate to where you put ``tromi_mobile.love`` in the File manager (the one you downloaded from the link in Install for TV section), just opening and Tromi should be launched.
# Differences from original Tromi
# Changes
> I must make this list to follow the used license (GNU GPL v3)<br>
> :no_entry: There are ***very much*** breaking changes right now, and I can't always finish this list. I may try hard to do it.
* No differences in gameplay
* **NO DIFFERENCES IN GAMEPLAY**
* Files will be saved into ``Android/data/org.love2d.android/tromi_mobile`` instead the location where the game files in
* Add ``simple-button`` module, made by me (SweetSea)
* All UIs are touch-able
* Add replay importer / exporter through clipboard
* UI are re-designed to compactible with touch screen
* Add on-screen buttons
* Replaced icons for 3 direction buttons (Left, Down, Right), using from Techmino's font (outdated image)
<img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/Replay_screen_differences.png">
* Add a special pre-made keybind for Android TV (only supports TV models have their remote has numerical area (0-9))<img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/SPOILER_tv_code.png">
* <details><summary>Changes the way to input secret code to activate Pentominoes mode</summary><img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/SPOILER_pento_code.png">To insert the left arrow, tap on the left, so does to right arrow.</details>
* Add a loading screen ~~(this need to be updated later)~~
* Replaced icons for 3 direction buttons (Left, Down, Right), using from Techmino's font.
* Add a special pre-made keybind for Android TV (only supports TV models have their remote has numerical area (0-9)).
* To use it, you have to activate TV mode. Type ``88663366`` by using your remote or external keyboard at the "Control method selection screen" (Tromi will show this screen at the first boot). After typing, Tromi will automatically use that keybind.
* To deactivate TV mode, press ``........`` (8 dots). ***WARNING:*** the keyboard method will be resetted, which mean if you have assigned another keybind for keyboard, it will also be erased.
* Change the way to input secret code to activate Pentominoes mode.
* Add a loading screen
* Update ``binser`` library, this fixes some weird bugs related to saving
* Replaced old Cambridge's ``config`` module with the new one inspired by "the sequel of Techmino"s ``SETTINGS`` module
* Add ``simple-button`` module, made by me (SweetSea)
* Replaced old Cambridge's ``config`` module with the new one inspired by "the sequel of Techmino"s ``SETTINGS`` module".
# TODO
- [ ] Add a way to export ~~replay~~ data for Android > 11
- [x] Add a way to export replay data for Android > 11
- [x] Revert ``bitser`` with ``binser`` (if and only if I can make it works)
- [x] Design a new on-screen buttons skin (the current one is come from [C₂₉H₂₅N₃O₅](https://github.com/C29H25N3O5), I am aware that it's not fit to Tromi's design language)
- [ ] Updating on-screen control configuration screen
- [ ] (Low priority) Design a new menu screen
- [x] Updating on-screen control configuration screen
- [x] (Low priority) Design a new menu screen
- [ ] Add user data management
- [ ] Redesign "the Control method selection" screen
- [ ] Redesign the replay screen
- [ ] Add shortcut to open replay converter at https://sweetsea-butimnotsweet.github.io/tromi_replay_converter
# License (GNU GPLv3)
Please read ``COPYING.txt`` for more information.<br>

View File

@@ -88,8 +88,8 @@ local L={
hollowLogo= 0xF008C,
toUp= 0xF008D,
toDown= 0xF008E,
toLeft= 0xF008F,
toRight= 0xF0090,
toLeft= 0xF0090,
toRight= 0xF008F,
checkMark= 0xF0091,
crossMark= 0xF0092,
musicMark= 0xF0093,

View File

@@ -94,6 +94,13 @@ function math.roundUnit(n,u)
return math.floor(n/u+.5)*u
end
---@return table
function table.pack(...)
local t = {...}
t.n = select('#', ...)
return t
end
---@param t1 table
---@param t2 table
---@return table t
@@ -143,15 +150,6 @@ function drawText(text, x, y, size, orientation, color)
love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5)
end
function drawBoldText(text, x, y, size, orientation, color)
if color == nil then color = {1, 1, 1, 1} end
love.graphics.setFont(FONT_bold)
love.graphics.setColor(0, 0, 0, 0.8)
love.graphics.printf(text, x+1, y+1, size*2, orientation, nil, 0.50)
love.graphics.setColor(color)
love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5)
end
function drawBigText(text, x, y, size, orientation, color)
if color == nil then color = {1, 1, 1, 1} end
love.graphics.setFont(FONT_big)

View File

@@ -1,9 +1,9 @@
local Object = require 'libs.classic'
local bit = require("bit")
local lualzw = require 'libs.lualzw'
local bitser = require 'libs.bitser'
local playedReadySE = false
local hiscore_pos
local Grid = require 'game.grid'
local Randomizer = require 'game.randomizer'
@@ -11,7 +11,9 @@ local Randomizer = require 'game.randomizer'
local GameMode = Object:extend()
function GameMode:new(player_name, input_file, replay_grade)
VCTRL.toggle(MOBILE and not input_file and not SETTINGS.tvMode)
-- VCTRL.toggle(MOBILE and not input_file and not SETTINGS.tvMode)
VCTRL.toggle(true)
VCTRL.reset()
if player_name == nil then self.training = true else self.training = false end
if input_file ~= nil then
@@ -149,7 +151,7 @@ function GameMode:readGradeHistory()
if self.grade > 1 then
local temp_grade = copy(self.grade_history); temp_grade[2] = 0
FILE.write(SAVE_DIR..self.player_name.."_grade_history.sav", temp_grade)
end
end
end
function GameMode:readHiScores()
@@ -979,7 +981,7 @@ function GameMode:drawScoringInfo()
love.graphics.rectangle("fill", 95, 80, 110, 180, 10, 10)
if not PENTO_MODE then drawText("Grade:", 100, 128, 1000, "left") end
-- Line & Level
if self.training or SETTINGS["lines"] then
if self.input_playback or SETTINGS["lines"] then
love.graphics.setColor(0,0,0,0.5)
love.graphics.rectangle("fill", 241, 407, 116, 40, 5, 5) --lines
love.graphics.setColor(0.05,0.05,0.05,1)
@@ -992,7 +994,7 @@ function GameMode:drawScoringInfo()
love.graphics.rectangle("fill", 68, 270, 140, 190, 10, 10)
love.graphics.setColor(0.05,0.05,0.05,1)
love.graphics.rectangle("fill", 65, 267, 140, 190, 10, 10)
drawBoldText(string.format("REPLAY IN PROGRESS\n\n\n\n\n\n\n\n\n%s", formatTime(self.frames)), 70, 275, 1000, "left")
drawText(string.format("REPLAY IN PROGRESS\n\n\n\n\n\n\n\n\n%s", formatTime(self.frames)), 70, 275, 1000, "left")
drawBigText(string.format("%s", self.grade), 100, 143, 1000, "left")
self:drawInputDisplay(103,185)
elseif not PENTO_MODE then
@@ -1073,6 +1075,7 @@ end
function GameMode:drawFrame()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setLineWidth(1)
love.graphics.line(216,80,216,80+(16*self.grid.height))
love.graphics.line(216+(16*self.grid.width),80,216+(16*self.grid.width),80+(16*self.grid.height))
love.graphics.line(216,80+(16*self.grid.height),216+(16*self.grid.width),80+(16*self.grid.height))

View File

@@ -64,7 +64,7 @@ function control_type.button:new(data)
r=data.r or 80, -- size
shape=data.shape or 'circle',
key=data.key or 'X',
iconSize=data.iconSize or 80,
iconSize=data.iconSize or 60,
alpha=data.alpha or 0.75,
quad=virtual_quad[data.key]
},self)
@@ -90,7 +90,7 @@ end
function control_type.button:press(_,_,id)
self.pressed=true
self.lastPressTime=love.timer.getTime()
self.pressing=id
self.pressingID=id
-- love.keypressed(self.key, love.keyboard.getScancodeFromKey(self.key))
SCENE:onInputPress{input=self.key,type="virtual"}
end
@@ -148,6 +148,7 @@ local touches={}
local global_toggle=false
VCTRL={}
VCTRL.focus=nil -- Focusing buttons
VCTRL.hasChanged = false
---@class VCTRL.data
---@field type 'button'
@@ -231,6 +232,13 @@ function VCTRL.draw(forceAlpha)
end
end
function VCTRL.reset()
for _, w in ipairs(VCTRL) do
if w.pressingID then touches[w.pressingID] = nil end
w:reset()
end
end
function VCTRL.exportAll()
local t = {}
for o, k in ipairs(VCTRL) do t[o] = k:export() end

View File

@@ -139,11 +139,11 @@ function button:isHovering(x,y)
end
---Trigger press action, only when ``self._hovering`` is true
function button:press(x, y, touchID)
if (touchID and self:isHovering(x, y) or self._hovering) and not self._pressed then
self.codeWhenPressed()
if self:isHovering(x, y) and not self._pressed then
self._touchID = touchID
self._pressed = true
self.codeWhenPressed()
self:draw()
return true
@@ -154,7 +154,7 @@ function button:release(x, y, touchID)
local valid = true
if touchID then
valid = touchID == self._touchID
elseif x and y then
else
valid = true
end
@@ -311,4 +311,13 @@ function BUTTON.release(list, x, y, touchID)
for _, v in pairs(list) do if v:release(x, y, touchID) then return true end end
end
--- Do a reset, useful for switching scenes
function BUTTON.reset(list)
for _, v in pairs(list) do
v._pressed = false
v._hovering = false
v._touchID = false
end
end
return BUTTON

View File

@@ -1,10 +1,8 @@
-- Fonts
FONT_tromi = love.graphics.newFont('res/fonts/Iosevka-Bold.ttf' , 28)
FONT_big = love.graphics.newFont('res/fonts/Iosevka-Heavy.ttf', 56)
FONT_bold = love.graphics.newFont('res/fonts/Iosevka-Heavy.ttf', 28)
-- Icons
FONT_tromi:setFallbacks(love.graphics.newFont('res/fonts/techmino_proportional.otf', 28))
FONT_bold :setFallbacks(love.graphics.newFont('res/fonts/techmino_proportional.otf', 28))
FONT_big :setFallbacks(love.graphics.newFont('res/fonts/techmino_proportional.otf', 56))
CHAR = require("char")
@@ -48,8 +46,6 @@ BUTTON.setDefaultOption{
if self.font == FONT_big then
drawBigText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor)
elseif self.font == FONT_bold then
drawBoldText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor)
else
drawText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor)
end

View File

@@ -2,17 +2,17 @@ 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/'
CONFIG_FILE = 'config.sav'
HIscoreFILE = 'hiscores.sav'
if not love.filesystem.getInfo(REPLAY_DIR) then
love.filesystem.createDirectory(REPLAY_DIR)
end
CONFIG_FILE = 'config.sav'
HIscoreFILE = 'hiscores.sav'
BACKGROUND_COLOR = {32/255, 120/255, 88/255}
CURRENT_OS = love.system.getOS()
MOBILE = CURRENT_OS == "Android" or CURRENT_OS == "iOS"
@@ -34,6 +34,7 @@ function ShowLoadingText(thing)
end
function love.load()
require 'funcs'
math.randomseed(os.time())
require "modules.file" "binser"
require "settings"
@@ -48,19 +49,11 @@ function love.load()
-- Now it's real time to load all stuffs!
require "load" -- Most game's resources are loaded in here
require "modules.scene"
require "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
SCENE = LoadingScene()
-- 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},
@@ -104,14 +97,10 @@ function love.draw()
-- 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)
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.pop()
end
@@ -156,8 +145,10 @@ function love.keypressed(key, scancode)
if scancode == "f4" then
SETTINGS["fullscreen"] = not SETTINGS["fullscreen"]
love.window.setFullscreen(SETTINGS["fullscreen"])
love.resize(love.graphics.getDimensions())
elseif scancode == "f2" and SCENE.title ~= "Input Config" and SCENE.title ~= "Game" then
SCENE = InputConfigScene()
elseif scancode == "f3" then SCENE = DataManagementScene()
elseif scancode == "f12" then LLDEBUGGER.requestBreak()
-- elseif scancode == "f11" then SETTINGS.firstTime = true
-- function keys are reserved
@@ -386,30 +377,24 @@ function love.errorhandler(msg)
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
if drawText == nil or FONT_tromi == nil then
love.audio.stop()
love.graphics.origin()
love.graphics.setFont(love.graphics.newFont(20))
return function()
love.event.pump()
for e, a, b, c in love.event.poll() do
if (
e == "quit" or
e == "mousepressed"
) then return 1 end
end
love.graphics.clear()
love.graphics.print(err[1]:sub(7).."\nTraceback:\n"..tracebacks)
love.graphics.present()
love.timer.sleep(0.001)
end
end
@@ -535,6 +520,9 @@ local main_bg_draw_frame = 0
local main_bg_last_color = nil
function MainBackground()
love.graphics.setColor(BACKGROUND_COLOR)
love.graphics.rectangle("fill", 0, 0, 640, 480)
if SETTINGS["music"] and not SOUNDS["bgm_title"]:isPlaying() then
SOUNDS["bgm_title"]:setVolume(0.3)
SOUNDS["bgm_title"]:play()

85
scene.lua Normal file
View File

@@ -0,0 +1,85 @@
local Object = require "libs.classic"
---@class SCENE
---@field title string
---@field extend function # Get a empty SCENE table
---
---@field new function
---@field update function
---@field render function
---@field onInputMove function
---@field onInputPress function
---@field onInputRelease function
SCENE = Object:extend()
function SCENE:new() end
function SCENE:update() end
function SCENE:render() end
-- You can use the class SCENE_onInput to show suggestions for `e` table
---@class SCENE_onInput
---@field type? "key"|"joystick"|"virtual"|"touch"|"mouse"|"wheel"
---
---@field input? # Action triggered<br>Only visible via keyboard and gamepad
---| "menu_decide"
---| "menu_back"
---| "left"
---| "right"
---| "up"
---| "down"
---| "rotate_left"
---| "rotate_right"
---| "rotate_left2"
---| "rotate_right2"
---
---@field key? love.KeyConstant Key pressed? Only visible via keyboard and gamepad
---@field scancode? love.Scancode Key pressed but on the US layout? Only visible via keyboard and gamepad
---
---@field x? number Only visible via touch and mouse
---@field y? number Only visible via touch and mouse
---@field dx? number # Delta X<br> Only visible via touch, mouse and wheel
---@field dy? number # Delta Y<br> Only visible via touch, mouse and wheel
---@field id? lightuserdata # Only visible via touch
---@field presses? number # Only visible via mouse
-- e in 4 below functions will contain different things based on it's type:
-- key - input, key, scancode
-- joystick - input, button, name
-- virtual - input
-- touch - x, y, dx, dy, id
-- mouse - x, y, dx, dy, presses
-- wheel - dx, dy
function SCENE:onInputMove(e) end
function SCENE:onInputPress(e) end
function SCENE:onInputRelease(e) end
LoadingScene = require "scene.loading"
GameScene = require "scene.game"
TrainingScene = require "scene.training"
NameEntryScene = require "scene.name_entry"
FullscreenScene = require "scene.fullscreen"
KeyConfigScene = require "scene.key_config"
StickConfigScene = require "scene.stick_config"
-- MusicToggleScene = require "scene.music_toggle"
-- LinesToggleScene = require "scene.lines_toggle"
TouchConfigScene = require "scene.touch_config"
TouchConfigPreviewScene = require "scene.touch_config_preview"
InputConfigScene = require "scene.input_config"
SettingsScene = require "scene.settings"
EraseHighScoresScene = require "scene.data.erase_high_scores"
ResetAllScene = require "scene.data.reset_all"
DataManagementScene = require "scene.data_management"
ReplaySelectScene = require "scene.replay"
ReplayTestScene = require"scene.replay_test"
AboutScene = require "scene.about"
ExitScene = require "scene.exit"
TitleScene = require "scene.title2"

139
scene/about.lua Normal file
View File

@@ -0,0 +1,139 @@
---@class SCENE
local AboutScene = SCENE:extend()
AboutScene.title = "About"
local current_page = 1
local maxPage = 2
local buttonList
local function changePage(rel)
current_page = (current_page + maxPage + rel - 1) % maxPage + 1
end
buttonList = {
BUTTON.new{
text = function()
if current_page < maxPage then
return ("%s Next (%s/%s)"):format(CHAR.key.right, current_page, maxPage)
else
return ("%s Back (%s/%s)"):format(CHAR.icon.toLeft, current_page, maxPage)
end
end,
textOrientation = "center",
x = 185, y = 440, w = 130, h = 30,
codeWhenReleased = function()
changePage(1)
BUTTON.reset(buttonList)
end
},
BUTTON.new{
text = CHAR.icon.home.." Title",
textOrientation = "center",
x = 325, y = 440, w = 130, h = 30,
codeWhenReleased = function() SCENE = TitleScene() end
}
}
function AboutScene:new()
current_page = 1
BUTTON.reset(buttonList)
end
function AboutScene:render()
MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 0, 0, 640, 480)
BUTTON.draw(buttonList)
if current_page == 1 then
-- Design & programming - Mycophobia
drawText ("Design & programming" , 20, 10, 180, "center")
drawBigText("mycophobia" , 20, 25, 180, "center")
drawText ("https://mycophobia.org" , 20, 60, 180, "center")
-- Cambridge - Based on
drawText ("Based on" , 230, 10, 180, "center")
drawBigText("Cambridge" , 230, 25, 180, "center")
drawText ("Cambridge contributors\nhttps://t-sp.in/cambridge", 230, 60, 180, "center")
-- Port to TV & mobile - SweetSea
drawText ("Port to TV & mobile" , 450, 10, 180, "center")
drawBigText("SweetSea" , 450, 25, 180, "center")
drawText ("https://github.com/\nSweetSea-ButImNotSweet" , 450, 60, 180, "center")
-- Design & programming - Mycophobia
drawText ("RNG Consultant" , 20, 120, 180, "center")
drawBigText("colour_thief" , 20, 135, 180, "center")
-- Design & programming - Mycophobia
drawText ("Launcher for Mac" , 450, 120, 180, "center")
drawBigText("nightmareci" , 450, 135, 180, "center")
drawText ("http://iblock.red" , 450, 170, 180, "center")
local other_text_y = 200
--- Other credit text, small text's y on the right = big text's y + 13, on the left: big text's y + 30
-- Music - Jerry Martin
drawBigText("Music", 0, other_text_y, 250, "right")
drawText("all rights reserved", 0, other_text_y + 30, 250, "right")
drawText("Jerry Martin - https://jerrymartinmusic.com \nJuraj Stanik - https://www.jurajstanik.com", 300, other_text_y + 13, 400, "left")
-- Background - PixaBays
drawBigText("Background", 0, other_text_y + 60, 250, "right")
drawText("by people on PixaBays", 0, other_text_y + 90, 250, "right")
drawText(
"Joe_hackney VisualSkyFX\n"..
"yokim Favorisxp Any_Ann",
300, other_text_y + 73, 400, "left"
)
-- Special thanks
drawBigText("Testing and/or\nCool Features", 0, other_text_y + 120, 250, "right")
drawText(
"netdoll esquatre Kirby703\n"..
"switchpalacecorner lindtobias\n"..
"zaphod77 Arch Nemesis dtet_enjoyer\n"..
"woozy Zircean AgentBasey Eden GT",
300, other_text_y + 133, 400, "left"
)
elseif current_page == 2 then
-- Main font
drawBigText("Font", 0, 10, 250, "right")
drawText("all used font are licensed under\nthe SIL Open Font License, v.1.1", 0, 40, 250, "right")
drawText(
"Iosevka - Renzhi Li (aka. Bellve Invis),\n(for game's UI interface and\n on-screen buttons' texture)\n\n"..
"Exo 2 for Techmino - C₂₉H₂₅N₃O₅, (for game's UI)\n\n"..
"Cascadia Code - Microsoft, used with Iosevka\nfor on-screen buttons' texture",
300, 23, 340, "left"
)
-- VCTRL
drawBigText("On-screen buttons\nimplementation", 0, 180, 250, "right")
drawText("UI's buttons: using simple-button module\nwritten by SweetSea\n\nIn-game on-screen control module is based on MrZ's VCTRL module in his games\nTexture made by SweetSea", 300, 193, 340, "left")
drawBigText("Special thanks", 25, 310, 460, "left")
drawText(
"The Absolute Plus - theabsolute.plus FYAD/Imp Zone Collective\
MrZ - https://github.com/MrZ626 C₂₉H₂₅N₃O₅ - https://github.com/C29H25N3O5\n\
AND ALL VERSION 1 PLAYERS "
, 25, 350, 600, "left")
end
end
---@param e SCENE_onInput
function AboutScene:onInputPress(e)
local key = e.input or e.key
if e.type == "touch" or e.type == "mouse" then
BUTTON.press(buttonList, e.x, e.y, e.id)
elseif key == "left" or key == "up" then changePage(-1)
elseif key == "right" or key == "down" then changePage( 1)
elseif e.input == "menu_back" or e.scancode == "escape" then
SCENE = TitleScene()
end
end
function AboutScene:onInputRelease(e)
if e.type == "touch" or e.type == "mouse" then
BUTTON.release(buttonList, e.x, e.y, e.id)
end
end
function AboutScene:onInputMove(e)
if e.type == "mouse" then
BUTTON.checkHovering(buttonList, e.x, e.y)
end
end
return AboutScene

View File

@@ -0,0 +1,81 @@
local EraseHighScoresScene = SCENE:extend()
EraseHighScoresScene.title = "Erase all high scores"
local selection_title = {"No", "Yes"}
local selection_icon = {
CHAR.icon.crossMark,
CHAR.icon.checkMark,
}
local menu_tip = "Are you sure you want to erase all your high scores?\n\nCAUTION!\nThis action CANNOT BE UNDONE!"
local settings_func = {
function() return DataManagementScene() end,
function()
love.filesystem.remove(HIscoreFILE)
love.window.showMessageBox("Done", "All high scores are erased!")
return DataManagementScene()
end,
}
function EraseHighScoresScene:new()
self.settings_menu_state = 1
end
function EraseHighScoresScene:changeOption(rel)
local len = #selection_title
self.settings_menu_state = (self.settings_menu_state + len + rel - 1) % len + 1
end
function EraseHighScoresScene:render()
MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 30, 60, 580, 85, 10, 10) -- Tromi
love.graphics.rectangle("fill", 30, 165, 580, 225, 10, 10) -- Menu
drawBigText(CHAR.icon.erase.." ERASE ALL HIGH SCORES?", 40, 85, 400, "left")
-- Selecting
love.graphics.setColor(0.4, 1, 1, 0.5)
love.graphics.rectangle("fill", 330, 135 + 40 * self.settings_menu_state, 270, 40)
-- Text
for i = 1, #selection_title do
drawText (selection_title[i], 365, 145 + 40 * i, 230, "left")
drawBigText(selection_icon [i], 335, 135 + 40 * i, 50, "left")
end
drawText(menu_tip, 45, 175, 610 - 15 - 330, "left")
end
---@param e SCENE_onInput
function EraseHighScoresScene:onInputPress(e)
if e.input == "menu_back" or e.scancode == "escape" then SCENE = TitleScene()
elseif e.input == "menu_decide" or e.key == "return" then
local s = settings_func[self.settings_menu_state]()
if s then SCENE = s end
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
elseif e.type == "touch" or e.type == "mouse" then
local x, y = e.x, e.y
local testOption = function(sel)
if sel ~= self.settings_menu_state then
self.settings_menu_state = sel
else
self:onInputPress{input = "menu_decide"}
end
end
if (
x >= 330 and x <= 600 and
y >= 175 and y <= 375
) then
local sel = math.floor((y - 175) / 40) + 1
if sel <= #settings_func then
testOption(sel)
end
end
end
end
return EraseHighScoresScene

93
scene/data/reset_all.lua Normal file
View File

@@ -0,0 +1,93 @@
local ResetAllScene = SCENE:extend()
ResetAllScene.title = "Erase all high scores"
local selection_title = {"No", "Yes"}
local selection_icon = {
CHAR.icon.crossMark,
CHAR.icon.checkMark,
}
local menu_tip = "ARE YOU SURE you want to RESET ALL?\n\nCAUTION: This will reset everything: accounts, replays, high scores and your settings!\n\nGame will restart after resetting."
local function recursivelyDelete(item)
if love.filesystem.getInfo(item,"directory") then
for _, child in ipairs(love.filesystem.getDirectoryItems(item)) do
recursivelyDelete(item..'/'..child)
love.filesystem.remove(item..'/'..child)
end
elseif love.filesystem.getInfo(item) then
love.filesystem.remove(item)
end
love.filesystem.remove(item)
end
local settings_func = {
function() return DataManagementScene() end,
function()
recursivelyDelete('')
love.window.showMessageBox("Done", "All your data erased\nQuitting game... Game will restart now!")
love.event.quit()
end,
}
function ResetAllScene:new()
self.settings_menu_state = 1
end
function ResetAllScene:changeOption(rel)
local len = #selection_title
self.settings_menu_state = (self.settings_menu_state + len + rel - 1) % len + 1
end
function ResetAllScene:render()
MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 30, 60, 580, 85, 10, 10) -- Tromi
love.graphics.rectangle("fill", 30, 165, 580, 225, 10, 10) -- Menu
drawBigText(CHAR.icon.erase.." RESET ALL?", 40, 85, 400, "left")
-- Selecting
love.graphics.setColor(0.4, 1, 1, 0.5)
love.graphics.rectangle("fill", 330, 135 + 40 * self.settings_menu_state, 270, 40)
-- Text
for i = 1, #selection_title do
drawText (selection_title[i], 365, 145 + 40 * i, 230, "left")
drawBigText(selection_icon [i], 335, 135 + 40 * i, 50, "left")
end
drawText(menu_tip, 45, 175, 610 - 15 - 330, "left")
end
---@param e SCENE_onInput
function ResetAllScene:onInputPress(e)
if e.input == "menu_back" or e.scancode == "escape" then SCENE = TitleScene()
elseif e.input == "menu_decide" or e.key == "return" then
local s = settings_func[self.settings_menu_state]()
if s then SCENE = s end
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
elseif e.type == "touch" or e.type == "mouse" then
local x, y = e.x, e.y
local testOption = function(sel)
if sel ~= self.settings_menu_state then
self.settings_menu_state = sel
else
self:onInputPress{input = "menu_decide"}
end
end
if (
x >= 330 and x <= 600 and
y >= 175 and y <= 375
) then
local sel = math.floor((y - 175) / 40) + 1
if sel <= #settings_func then
testOption(sel)
end
end
end
end
return ResetAllScene

96
scene/data_management.lua Normal file
View File

@@ -0,0 +1,96 @@
local DataManagementScene = SCENE:extend()
DataManagementScene.title = "Data Management"
local data_title = {
"Open save folder",
"Manage accounts (WIP)",
"Erase all high scores",
"RESET ALL!",
"Back"
}
local data_icon = {
CHAR.key .windows,
CHAR.icon.menu,
CHAR.icon.erase,
CHAR.icon.erase,
CHAR.icon.home,
}
local data_explaination = {
"(Only for PC)\nOpen save folder in a new window",
"You can view and delete your accounts here.",
"Erase all your high scores\nThis will make high score table go back to default",
"Erase all accounts, replays and all high scores!",
"Back to main menu"
}
local NULL = function() end
local settings_func = {
function() love.system.openURL(love.filesystem.getSaveDirectory()) end,
NULL,
function() return EraseHighScoresScene() end,
function() return ResetAllScene() end,
function() return TitleScene() end,
}
function DataManagementScene:new()
self.data_menu_state = 1
end
function DataManagementScene:changeOption(rel)
local len = #data_title
self.data_menu_state = (self.data_menu_state + len + rel - 1) % len + 1
end
function DataManagementScene:render()
MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 30, 60, 580, 85, 10, 10) -- Tromi
love.graphics.rectangle("fill", 30, 165, 580, 225, 10, 10) -- Menu
drawBigText(CHAR.icon.export.." DATA MANAGEMENT", 40, 85, 400, "left")
-- Selecting
love.graphics.setColor(0.4, 1, 1, 0.5)
love.graphics.rectangle("fill", 40, 135 + 40 * self.data_menu_state, 270, 40)
-- Text
for i = 1, #data_title do
drawText (data_title[i], 85, 145 + 40 * i, 230, "left")
drawBigText(data_icon [i], 45, 135 + 40 * i, 50, "left")
end
drawText(data_explaination[self.data_menu_state], 330, 175, 610 - 15 - 330, "left")
end
---@param e SCENE_onInput
function DataManagementScene:onInputPress(e)
if e.input == "menu_back" or e.scancode == "escape" then SCENE = TitleScene()
elseif e.input == "menu_decide" or e.key == "return" then
local s = settings_func[self.data_menu_state]()
if s then SCENE = s end
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
elseif e.type == "touch" or e.type == "mouse" then
local x, y = e.x, e.y
local testOption = function(sel)
if sel ~= self.data_menu_state then
self.data_menu_state = sel
else
self:onInputPress{input = "menu_decide"}
end
end
if (
x >= 40 and x <= 310 and
y >= 175 and y <= 375
) then
local sel = math.floor((y - 175) / 40) + 1
if sel <= #settings_func then
testOption(sel)
end
end
end
end
return DataManagementScene

View File

@@ -8,14 +8,5 @@ function ExitScene:update()
love.event.quit()
end
function ExitScene:render()
end
function ExitScene:changeOption(rel)
end
function ExitScene:onInputPress(e)
end
return ExitScene

View File

@@ -3,7 +3,6 @@ GameScene.title = "Game"
local tas = false
-- 70 295
local buttonList = {
BUTTON.new{
text = "Rotate Left\n Pause/Frame Step",
@@ -45,17 +44,17 @@ local buttonList = {
local menuKey -- MENU key used to go main menu XD
function GameScene:new(player_name, replay_file, replay_grade)
VCTRL[9].show = false
menuKey = BUTTON.new{
text = "MENU",
x = 265, y = 0, w = 60, h = 25,
text = CHAR.icon.menu.." MENU",
x = 10, y = 10, w = 70, h = 30,
codeWhenReleased = function()
if self.game.input_playback or self.game.game_over or self.game.completed then
SCENE = TitleScene()
end
end
}
VCTRL[9].show = false
BUTTON.reset(buttonList)
game_mode = require 'game.gamemode'
if PENTO_MODE then
@@ -89,7 +88,7 @@ end
function GameScene:update(nosound, tas_update)
local inputs = {}
if tas then
if tas then
while self.game.are > 2 do
self.game:update(inputs, self.ruleset)
end

View File

@@ -48,16 +48,16 @@ end
function KeyConfigScene:render()
MainBackground()
for i, input in ipairs(configurable_inputs) do
drawText(input_names[input], 40, 50 + i * 20, 200, "left")
drawText(input_names[input], 40, 60 + i * 20, 200, "left")
if self.set_inputs[input] then
drawText(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
drawText(self.set_inputs[input], 240, 60 + i * 20, 300, "left")
end
end
if self.input_state > #configurable_inputs then
drawText("Press Enter/Confirm Selection to confirm, delete/backspace to retry" .. (SETTINGS.input and ", escape/Go Back to cancel" or ""),0,0,1000)
drawText("Press Enter/Confirm Selection to confirm, delete/backspace to retry" .. (SETTINGS.input.keys and ", esc/Go Back to cancel" or ""),0,0,1000)
else
drawText("Press key input for " .. input_names[configurable_inputs[self.input_state]] .. ", tab to skip, escape to cancel",0,0,1000)
drawText("Press any key from other input than keyboard will also skip.\nFunction keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20,1000)
drawText("Press key input for " .. input_names[configurable_inputs[self.input_state]] .. ", escape to cancel\nPress tab on keyboard, or any key from other inputs, to skip",0,0,1000)
drawText("Function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 35,1000)
end
end

View File

@@ -1,21 +1,9 @@
local LinesToggleScene = SCENE:extend()
LinesToggleScene.title = "Show lines during game:"
function LinesToggleScene:new()
end
function LinesToggleScene:update()
SETTINGS["lines"] = not SETTINGS["lines"]
SCENE = TitleScene()
end
function LinesToggleScene:render()
end
function LinesToggleScene:changeOption(rel)
end
function LinesToggleScene:onInputPress(e)
end
return LinesToggleScene

10
scene/loading.lua Normal file
View File

@@ -0,0 +1,10 @@
local LoadingScene = SCENE:extend()
function LoadingScene.update()
SCENE = SETTINGS.firstTime and InputConfigScene(true) or TitleScene()
end
function LoadingScene.render()
love.graphics.draw(LOADING_IMAGE_FILE,0,0,0,0.5)
end
return LoadingScene

View File

@@ -1,21 +1,9 @@
local MusicToggleScene = SCENE:extend()
MusicToggleScene.title = "Play music during game:"
function MusicToggleScene:new()
end
function MusicToggleScene:update()
SETTINGS["music"] = not SETTINGS["music"]
SCENE = TitleScene()
end
function MusicToggleScene:render()
end
function MusicToggleScene:changeOption(rel)
end
function MusicToggleScene:onInputPress(e)
end
return MusicToggleScene
return MusicToggleScene

View File

@@ -3,33 +3,37 @@ NameEntryScene.title = "Game Start"
local buttonList = {
BUTTON.new{
text = "\nCHAR", font = FONT_big,
text = "\nCHAR", font = FONT_big,
x = 25, y = 120, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "left"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "left"} end,
},
BUTTON.new{
text = "\nCHAR", font = FONT_big,
text = "\nCHAR", font = FONT_big,
x = 115, y = 120, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "right"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "right"} end,
},
BUTTON.new{
text = "\nESC", font = FONT_big,
text = "\nESC", font = FONT_big,
x = 25, y = 210, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "menu_back"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "menu_back"} end,
},
BUTTON.new{
text = "\nENTER", font = FONT_big,
text = "\nENTER", font = FONT_big,
x = 115, y = 210, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "menu_decide"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "menu_decide"} end,
},
BUTTON.new{
text = CHAR.key.keyboard.." Open OSK", font = FONT_big,
x = 25, y = 300, w = 170, h = 40,
codeWhenReleased = function() love.keyboard.setTextInput(true, 215, 175, 160, 160) end
}
}
local Grid = require 'game.grid'
local bitser = require 'libs.bitser'
function NameEntryScene:new()
VCTRL.toggle(false)
@@ -61,7 +65,6 @@ function NameEntryScene:new()
self.hi_scores = {"TRO",0,"MIT",0,"ROM",0,"ITR",0,"OMI",0}
end
end
function NameEntryScene:drawGradeList(left, top)
love.graphics.setColor(0,0,0,0.5)
love.graphics.rectangle("fill", left+3, top+3, 200, 240, 10, 10)
@@ -97,10 +100,8 @@ function NameEntryScene:render()
love.graphics.setColor(0.05,0.05,0.05,1)
love.graphics.rectangle("fill", 397, 292, 130, 130, 10, 10)
drawText("Best scores:", 410, 297, 1000, "left")
i = 2
while i <= 10 do
for i = 2, 10, 2 do
drawText(self.hi_scores[i-1]..' - '..self.hi_scores[i], 410, 297+(i*10), 1000, "left")
i = i + 2
end
if self.entry_pos == 4 then
drawText('Press confirm\nto play', 255, 290, 1000)
@@ -138,28 +139,43 @@ function NameEntryScene:onInputMove(e)
end
end
function NameEntryScene:getPlayInfo(player_name)
if love.filesystem.getInfo((SAVE_DIR..player_name.."_grade_history.sav")) then
grade_history = FILE.read(SAVE_DIR..player_name.."_grade_history.sav")
self.grade = grade_history[1]
self.wins = grade_history[2]
self.plays = grade_history[4]
else
self.grade, self.win, self.plays = 0, 0, 0
end
return self.grade, self.win, self.plays
end
function NameEntryScene:onInputPress(e)
local name = string.lower(self.name_entry[1]..self.name_entry[2]..self.name_entry[3])
if e.type == "mouse" or e.type == "touch" then
BUTTON.press(buttonList, e.x, e.y, e.id)
elseif e.key and #e.key == 1 then
local pos = string.find("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.", string.upper(e.key), 1, true)
if pos then
if self.entry_pos <= 3 then
self.char_pos = pos
self.name_entry[self.entry_pos] = string.upper(e.key)
self.name_entry[self.entry_pos + 1] = string.upper(e.key)
end
if self.entry_pos == 3 then self:getPlayInfo(name) end
self.entry_pos = math.min(self.entry_pos + 1, 4)
end
elseif e.input == "menu_decide" or e.input == "rotate_left" or e.scancode == "return" then
if self.entry_pos == 4 then
BUTTON.release(buttonList, e.x, e.y, e.id)
SETTINGS['last_entry'] = name:upper()
SCENE = GameScene(name:lower())
else
if self.entry_pos == 3 then
name = string.lower(self.name_entry[1]..self.name_entry[2]..self.name_entry[3])
if love.filesystem.getInfo((SAVE_DIR..name.."_grade_history.sav")) then
grade_history = FILE.read(SAVE_DIR..name.."_grade_history.sav")
self.grade = grade_history[1]
self.wins = grade_history[2]
self.plays = grade_history[4]
end
end
if self.entry_pos < 3 then
self.name_entry[self.entry_pos] = self.chars:sub(self.char_pos, self.char_pos)
self.name_entry[self.entry_pos+1] = self.chars:sub(self.char_pos, self.char_pos)
end
if self.entry_pos == 3 then self:getPlayInfo(name)
else
self.name_entry[self.entry_pos ] = self.chars:sub(self.char_pos, self.char_pos)
self.name_entry[self.entry_pos+1] = self.chars:sub(self.char_pos, self.char_pos)
end
self.entry_pos = self.entry_pos + 1
end
elseif e.input == "left" or e.scancode == "left" then

View File

@@ -160,10 +160,10 @@ function ReplaySelectScene:onInputPress(e)
end
elseif e.input == "rotate_left" then -- Export
local plain_replay_data = love.data.encode("string", "base64", love.filesystem.read(REPLAY_DIR..selected_replay))
love.system.setClipboardText(("BEGINNING_OF_TROMI_REPLAY|%s|%s|END_OF_TROMI_REPLAY"):format(selected_replay, plain_replay_data))
love.system.setClipboardText(("BEGIN_OF_TROMI_REPLAY|%s|%s|END_OF_TROMI_REPLAY"):format(selected_replay, plain_replay_data))
elseif e.input == "rotate_right" then -- Import
local input_data = love.system.getClipboardText()
if input_data:find("BEGINNING_OF_TROMI_REPLAY|", 1, true) == 1 and input_data:find("|END_OF_TROMI_REPLAY", 1, true) == #input_data - 19 then
if input_data:find("BEGIN_OF_TROMI_REPLAY|", 1, true) == 1 and input_data:find("|END_OF_TROMI_REPLAY", 1, true) == #input_data - 19 then
local data_part = input_data:sub(27, #input_data - 20)
local separator_pos = data_part:find("|", 1, true)
local replay_name = data_part:sub(1, separator_pos - 1)
@@ -171,8 +171,10 @@ function ReplaySelectScene:onInputPress(e)
local replay_data = love.data.decode("string", "base64", data_part:sub(separator_pos + 1))
love.filesystem.write(replay_path, replay_data)
BUTTON.reset(buttonList)
SCENE = ReplayTestScene(replay_name)
else
BUTTON.reset(buttonList)
SCENE = ReplayTestScene()
end
elseif e.input == "up" or e.scancode == "up" then

View File

@@ -3,9 +3,12 @@ local ReplayTestScene = SCENE:extend()
local GAME
local error_message
local valid_data
local prev_scene
function ReplayTestScene:new(input_file)
prev_scene = SCENE
if not input_file then
valid_data = false
return
@@ -27,7 +30,10 @@ function ReplayTestScene:new(input_file)
end
function ReplayTestScene:render()
MainBackground()
prev_scene:render()
love.graphics.setColor(0, 0, 0, 0.8)
love.graphics.rectangle("fill", 0, 0, 640, 480)
if valid_data then
if error_message then
drawText("Replay test failed! Data corrupted!", 80, 40, 1000)
@@ -39,7 +45,7 @@ function ReplayTestScene:render()
end
else
drawText("Replay test failed! Not Tromi's replay data", 80, 40, 1000)
drawText("Press any key to go back, and check your device's clipboard again!", 80, 100, 1000)
drawText("Press any key to go back, and check your device's clipboard again!", 80, 70, 1000)
end
end

95
scene/settings.lua Normal file
View File

@@ -0,0 +1,95 @@
local SettingsScene = SCENE:extend()
SettingsScene.title = "Settings"
local settings_title = {
"Music",
"Lines",
"Fullscreen (F4)",
"Input configuration (F2)",
"Back",
}
local settings_explaination = {
"Enable music?\nThis does not apply to sound effects.",
"Show level and lines counter?\nThis setting is ignored when replaying.",
"Enter or leave fullscreen\nYou can press F4 key at any screen to do this quick.",
"This is where you can re-configure your keybinds.\nYou can press F2 on the keyboard to open this quick\n\nTip for TV:\n\t88663366: enable TV mode.\n\t........: disable TV mode",
"Back to main menu"
}
local settings_func = {
function()
SETTINGS["music"] = not SETTINGS["music"]
love.audio.stop()
end,
function() SETTINGS["lines"] = not SETTINGS["lines"] end,
function() love.keypressed("f4", "f4") end,
InputConfigScene,
function() return TitleScene() end,
}
function SettingsScene:new()
self.settings_menu_state = 1
end
function SettingsScene:changeOption(rel)
local len = #settings_title
self.settings_menu_state = (self.settings_menu_state + len + rel - 1) % len + 1
end
function SettingsScene:render()
MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 30, 60, 580, 85, 10, 10) -- Tromi
love.graphics.rectangle("fill", 30, 165, 580, 225, 10, 10) -- Menu
drawBigText(CHAR.icon.settings.." SETTINGS", 40, 85, 200, "left")
-- Selecting
love.graphics.setColor(0.4, 1, 1, 0.5)
love.graphics.rectangle("fill", 40, 135 + 40 * self.settings_menu_state, 270, 40)
-- Text
for i = 1, #settings_title do
drawText(settings_title[i], 45, 145 + 40 * i, 230, "left")
end
drawBigText(SETTINGS["music"] and CHAR.icon.checkMark or CHAR.icon.crossMark, 260, 175, 50, "center")
drawBigText(SETTINGS["lines"] and CHAR.icon.checkMark or CHAR.icon.crossMark, 260, 215, 50, "center")
drawBigText(love.window.getFullscreen() and CHAR.icon.checkMark or CHAR.icon.crossMark, 260, 255, 50, "center")
drawBigText(CHAR.key.keyboard , 260, 295, 50, "center")
drawBigText(CHAR.icon.home , 260, 335, 50, "center")
drawText(settings_explaination[self.settings_menu_state], 330, 175, 610 - 15 - 330, "left")
end
---@param e SCENE_onInput
function SettingsScene:onInputPress(e)
if e.input == "menu_back" or e.scancode == "escape" then SCENE = TitleScene()
elseif e.input == "menu_decide" or e.key == "return" then
local s = settings_func[self.settings_menu_state]()
if s then SCENE = s end
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
elseif e.type == "touch" or e.type == "mouse" then
local x, y = e.x, e.y
local testOption = function(sel)
if sel ~= self.settings_menu_state then
self.settings_menu_state = sel
else
self:onInputPress{input = "menu_decide"}
end
end
if (
x >= 40 and x <= 310 and
y >= 175 and y <= 375
) then
local sel = math.floor((y - 175) / 40) + 1
if sel <= #settings_func then
testOption(sel)
end
end
end
end
return SettingsScene

View File

@@ -48,13 +48,13 @@ end
function StickConfigScene:render()
MainBackground()
for i, input in ipairs(configurable_inputs) do
drawText(input_names[input], 40, 50 + i * 20, 200, "left")
drawText(input_names[input], 40, 60 + i * 20, 200, "left")
if self.set_inputs[input] then
drawText(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
drawText(self.set_inputs[input], 240, 60 + i * 20, 300, "left")
end
end
if self.input_state > #configurable_inputs then
drawText("Press enter/Confirm Selection to confirm, delete/backspace to retry" .. (SETTINGS.input and ", escape/Go Back to cancel" or ""), 0, 0, 1000)
drawText("Press enter/Confirm Selection to confirm, delete/backspace to retry" .. (SETTINGS.input.joysticks and ", esc/Go Back to cancel" or ""), 0, 0, 1000)
else
drawText("Press joystick input for " .. input_names[configurable_inputs[self.input_state]] .. ", tab to skip, escape to cancel", 0, 0, 1000)
end

View File

@@ -15,8 +15,6 @@ local main_menu_screens = {
}
function TitleScene:new()
VCTRL.clearAll() -- Reset the RESTART button state
VCTRL.new(SETTINGS.input.virtual)
if SOUNDS['bgm_firsthalf']:isPlaying() or SOUNDS['bgm_secondhalf']:isPlaying() or not SETTINGS["music"] then
love.audio.stop()
end
@@ -116,7 +114,6 @@ function TitleScene:onInputPress(e)
if self.main_menu_state ~= selecting then
self.main_menu_state = selecting
else
VCTRL.toggle(true)
SCENE = main_menu_screens[selecting]()
end
end

164
scene/title2.lua Normal file
View File

@@ -0,0 +1,164 @@
---@class SCENE
local Title2Scene = SCENE:extend()
Title2Scene.title = "Title"
local input_code = {}
local main_menu_title = {
"New game" ,
"Replay" ,
"Data management" ,
"Mobile port repository",
"About" ,
"Max gravity Training",
"Leaderboard" ,
"Settings" ,
"Official homepage" ,
"Exit game" ,
}
local half_pos = math.roundUnit(#main_menu_title / 2)
local main_menu_scenes = {
NameEntryScene,
ReplaySelectScene,
DataManagementScene,
function() love.system.openURL("https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile") end,
AboutScene,
TrainingScene,
function() love.system.openURL("https://mycophobia.org/forums/viewtopic.php?t=29") end,
SettingsScene,
function() love.system.openURL("https://mycophobia.org/tromi") end,
ExitScene
}
local main_menu_icons = {
CHAR.icon.play,
CHAR.icon.rewind,
CHAR.icon.export,
CHAR.icon.home,
CHAR.icon.info,
CHAR.icon.toDown,
CHAR.icon.globe,
CHAR.icon.settings,
CHAR.icon.home,
CHAR.icon.back,
}
function Title2Scene:new()
if SOUNDS['bgm_firsthalf']:isPlaying() or SOUNDS['bgm_secondhalf']:isPlaying() or not SETTINGS["music"] then
love.audio.stop()
end
self.main_menu_state = 1
PENTO_MODE = false
input_code = {0,0,0,0,0,0,0,0}
end
function Title2Scene:changeOption(rel)
local len = #main_menu_title
self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1
end
function Title2Scene:render()
MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 30, 60, 580, 85, 10, 10) -- Tromi
love.graphics.rectangle("fill", 30, 165, 580, 225, 10, 10) -- Menu
drawBigText("Tromi", 40, 65, 100, "left")
drawText("Mobile 1.0 - PC 2.3", 150, 78, 200, "left")
drawText("https://mycophobia.org\nhttps://github.com/SweetSea-ButImNotSweet/", 40, 100, 300, "left")
if PENTO_MODE then
drawBigText("PENTO MODE", 400, 85, 200, "right")
end
love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.setLineWidth(1)
love.graphics.line(320, 175, 320, 375)
-- Selecting
love.graphics.setColor(0.4, 1, 1, 0.5)
if self.main_menu_state > half_pos then
love.graphics.rectangle("fill", 330, 135 + 40 * (self.main_menu_state - half_pos), 270, 40)
else
love.graphics.rectangle("fill", 40, 135 + 40 * self.main_menu_state, 270, 40)
end
-- Text
for i = 1, half_pos do
drawText(main_menu_title[i] , 45, 145 + 40 * i, 230, "right")
drawText(main_menu_icons[i] or '', 285, 145 + 40 * i, 20, "center")
end
for i = half_pos + 1, #main_menu_title do
drawText(main_menu_title[i] , 365, 145 + 40 * (i - half_pos), 230, "left")
drawText(main_menu_icons[i] or '', 335, 145 + 40 * (i - half_pos), 20, "center")
end
end
local function checkCode(c)
if not PENTO_MODE then
table.insert(input_code, c)
if #input_code > 8 then
table.remove(input_code, 1)
end
local code_string = table.concat(input_code, ',')
if (
code_string == "-1,-1,-1,-1,1,1,1,1" or
code_string == "2,2,2,2,2,2,2,2"
) then
PENTO_MODE = true
end
end
end
---@param e SCENE_onInput
function Title2Scene:onInputPress(e)
if e.input == "menu_back" or e.scancode == "escape" then SCENE = TitleScene()
elseif e.input == "menu_decide" or e.key == "return" then
local s = main_menu_scenes[self.main_menu_state]()
if s then SCENE = s end
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
elseif e.input == "left" or e.scancode == "left" then
self:changeOption(-half_pos)
checkCode(-1)
elseif e.input == "right" or e.scancode == "right" then
self:changeOption(half_pos)
checkCode(1)
elseif e.type == "touch" or e.type == "mouse" then
local x, y = e.x, e.y
local testOption = function(sel)
if sel ~= self.main_menu_state then
self.main_menu_state = sel
else
self:onInputPress{input = "menu_decide"}
end
end
-- 40 175 320 375 320 175 600 375
if y >= 175 and y <= 375 then
local sel = math.floor((y - 175) / 40) + 1
if x >= 40 and x <= 310 and sel <= half_pos then
testOption(sel)
elseif (
x >= 330 and x <= 600 and
sel >= 1 and sel + half_pos <= #main_menu_scenes
) then
testOption(sel + half_pos)
end
elseif (
x >= 460 and y >= 85 and
x <= 600 and y <= 125
) then
checkCode(2)
end
end
end
return Title2Scene

View File

@@ -5,13 +5,11 @@ TouchConfigScene.title = "Touchscreen config"
local Grid = require 'game.grid'
local buttonList
local sliderList
local sliderList = {}
---@class VCTRL.data
local focusingButton
---@type number
local snapUnit = 1
---@type boolean
local hasChanged
---@type function
local function exitSceneFunc(saved)
@@ -29,23 +27,23 @@ buttonList = {
showToggle = BUTTON.new{
text = function()
if focusingButton then
return focusingButton.show and "[SHOW]\nHide" or "Show\n[HIDE]"
return focusingButton.show and ">SHOW<\nhide" or "show\n>HIDE<"
else
return "Show\nHide"
return "show\nhide"
end
end,
x = 275, y = 5, w = 50, h = 75,
codeWhenReleased = function ()
x = 400, y = 110, w = 60, h = 40,
codeWhenReleased = function()
if focusingButton then
focusingButton.show = not focusingButton.show
hasChanged = true
VCTRL.hasChanged = true
end
end,
update = function(self) self.textColor = focusingButton and {1, 1, 1} or {0.5, 0.5, 0.5} end
},
previewToggle = BUTTON.new{
text = "Preview\nON",
x = 570, y = 35, w = 60, h = 40,
x = 570, y = 60, w = 60, h = 40,
codeWhenReleased = function()
VCTRL.release()
BUTTON.release(buttonList)
@@ -54,7 +52,7 @@ buttonList = {
},
resetAll = BUTTON.new{
text = "RESET\nALL",
x = 570, y = 80, w = 60, h = 40,
x = 500, y = 110, w = 60, h = 40,
codeWhenReleased = function()
local selection = love.window.showMessageBox(
"Save config?", "Are you really sure about RESETTING ALL touchscreen configuration?",
@@ -63,7 +61,7 @@ buttonList = {
)
if selection == 1 then
VCTRL.focus = nil; focusingButton = nil
hasChanged = false
VCTRL.hasChanged = false
VCTRL.clearAll()
VCTRL.new(SETTINGS.__default__.input.virtual)
SETTINGS.input.virtual = SETTINGS.__default__.input.virtual
@@ -72,9 +70,9 @@ buttonList = {
},
menuScreen = BUTTON.new{
text = "MENU",
x = 570, y = 5, w = 60, h = 25,
x = 570, y = 10, w = 60, h = 40,
codeWhenReleased = function()
if hasChanged or SETTINGS.firstTime then
if VCTRL.hasChanged or SETTINGS.firstTime then
local selection = love.window.showMessageBox(
"Save config?", "Do you want to save your changes before exiting?",
{"Save", "Discard", "Keep editing", escapebutton = 3, enterbutton = 1},
@@ -98,45 +96,59 @@ buttonList = {
end
}
}
sliderList = {}
sliderList.buttonSize = newSlider(
200, 30, 120, 0, 0, 120,
function(v)
if focusingButton then
v = math.roundUnit(v, 5)
if focusingButton.r ~= v then
focusingButton.r = v
VCTRL.hasChanged = true
end
sliderList.buttonSize.value = v / 120
end
end,
{width = 40}
)
sliderList.iconSize = newSlider(
480, 30, 120, 0, 0, 100,
function(v)
if focusingButton then
v = math.roundUnit(v, 5)
if focusingButton.iconSize ~= v then
focusingButton.iconSize = v
VCTRL.hasChanged = true
end
sliderList.iconSize.value = v / 100
end
end,
{width = 40}
)
sliderList.opacity = newSlider(
155, 20+5, 120, 100, 0, 100,
200, 80, 120, 0, 0, 1,
function()
local v
if focusingButton then
v = math.roundUnit(sliderList.opacity.value, 0.01)
if focusingButton.alpha~=v then
focusingButton.alpha = v
hasChanged = true
VCTRL.hasChanged = true
end
sliderList.opacity.value = v
end
end,
{width = 30}
)
sliderList.size = newSlider(
155, 60+2.5, 120, 45, 0, 120,
function(v)
if focusingButton then
local v = math.roundUnit(v, 5)
if focusingButton.r ~= v then
focusingButton.r = v
hasChanged = true
end
sliderList.size.value = v / 120
end
end,
{width = 30}
{width = 40}
)
local gridSizeTable = {1, 2, 5, 10, 20, 50, 100}
sliderList.gridSize = newSlider(
405, 50, 100, 1, 1, #gridSizeTable - 1,
480, 80, 120, 1, 1, #gridSizeTable - 1,
function()
local v = math.roundUnit(sliderList.gridSize.value, 1 / 6)
local f = #gridSizeTable - 1
local v = math.roundUnit(sliderList.gridSize.value, 1 / f)
sliderList.gridSize.value = v
snapUnit = gridSizeTable[math.roundUnit(v * (#gridSizeTable - 1) + 1)]
snapUnit = gridSizeTable[math.roundUnit(v * f + 1)]
end,
{width = 30}
{width = 40}
); sliderList.gridSize.forceLight = true
local function sliderList_draw()
@@ -177,13 +189,15 @@ function TouchConfigScene:update()
if VCTRL.focus~=focusingButton then
focusingButton = VCTRL.focus
sliderList.opacity.value = focusingButton.alpha
sliderList.size.value = focusingButton.r / 120
sliderList.buttonSize.value = focusingButton.r / 120
sliderList.iconSize.value = focusingButton.iconSize / 100
end
BUTTON.update(buttonList)
sliderList_update()
end
local string_format = string.format
function TouchConfigScene:render()
MainBackground()
@@ -206,19 +220,16 @@ function TouchConfigScene:render()
end
love.graphics.setColor(0, 0, 0, 0.7)
-- Opacity and Size
love.graphics.rectangle("fill", 10, 5, 267, 75)
-- Snap to grid
love.graphics.rectangle("fill", 330, 5, 150, 75)
love.graphics.rectangle("fill", 5, 5, 560, 100)
-- Button Size
drawText(string_format("Size (buttons)\n%14.1d", focusingButton and focusingButton.r or 0), 10, 13, 100, "left")
-- Icon size
drawText(string_format("Size (icons)\n%13.1d%%", focusingButton and focusingButton.iconSize or 0), 290, 13, 100, "left")
-- Opacity
drawText("Opacity", 20, 15, 100, "left")
drawText(string.format("%3.1d%%", focusingButton and focusingButton.alpha * 100 or 0), 225, 15, 40, "left")
-- Size
drawText("Size", 20, 55, 100, "left")
drawText(string.format("%3.1dpx", focusingButton and focusingButton.r or 0), 225, 55, 40, "left")
drawText(string_format("Opacity\n%13.1d%%", focusingButton and focusingButton.alpha * 100 or 0), 10, 63, 100, "left")
-- Snap to grid
drawText(string.format("Snap to grid: %3s", snapUnit), 345, 15, 140, "left")
drawText(string_format("Snap to grid\n%14.1d", snapUnit), 290, 63, 100, "left")
for _, v in ipairs(VCTRL) do
if v ~= focusingButton then
@@ -245,10 +256,8 @@ end
---@param e SCENE_onInput
function TouchConfigScene:onInputMove(e)
if e.type == "touch" or (e.type == "mouse" and love.mouse.isDown(1)) then
if VCTRL.drag(e.dx, e.dy, e.id or 1) then hasChanged = true end
end
if e.type == "mouse" then
if VCTRL.drag(e.dx, e.dy, e.id or 1) then VCTRL.hasChanged = true end
elseif e.type == "mouse" then
BUTTON.checkHovering(buttonList, e.x, e.y)
end
end
@@ -258,7 +267,8 @@ function TouchConfigScene:onInputPress(e)
if not (
VCTRL.press(e.x, e.y, e.id and e.id or 1, true) or
BUTTON.press(buttonList, e.x, e.y, e.id) or
(e.x >= 80 and e.x <= 230 and e.y >= 10 and e.y <= 77)
(e.x >= 120 and e.x <= 280 and e.y >= 10 and e.y <= 100) or
(e.x >= 400 and e.x <= 560 and e.y >= 10 and e.y <= 100)
) then
VCTRL.focus = nil
focusingButton = nil

View File

@@ -8,7 +8,7 @@ local buttonList
buttonList = {
previewToggle = BUTTON.new{
text = "Preview\nOFF",
x = 570, y = 35, w = 60, h = 40,
x = 570, y = 60, w = 60, h = 40,
codeWhenReleased = function()
VCTRL.release()
BUTTON.release(buttonList)
@@ -16,8 +16,6 @@ buttonList = {
end
},
}
local sliderList = {}
local secret_grade_grid = {}
do
local colour_names = {'R', 'O', 'Y', 'G', 'C', 'B', 'M'}
@@ -80,13 +78,17 @@ end
function TouchConfigPreviewScene:onInputPress(e)
if e.type ~= "virtual" and e.input == 'menu_back' then SCENE = InputConfigScene() end
if e.type == "mouse" or e.type == "touch" then
BUTTON.press(buttonList, e.x, e.y, e.id)
if not BUTTON.press(buttonList, e.x, e.y, e.id) then
VCTRL.press(e.x, e.y, e.id or 1)
end
end
end
---@param e SCENE_onInput
function TouchConfigPreviewScene:onInputRelease(e)
if e.type == "mouse" or e.type == "touch" then
BUTTON.release(buttonList, e.x, e.y, e.id)
if not BUTTON.release(buttonList, e.x, e.y, e.id) then
VCTRL.release(e.id or 1)
end
end
end

View File

@@ -1,14 +1,15 @@
local TrainingScene = SCENE:extend()
TrainingScene.title = "Max Gravity Training"
local menuKey
local menuKey = BUTTON.new{
text = CHAR.icon.menu.." MENU",
x = 10, y = 10, w = 70, h = 30,
codeWhenReleased = function() SCENE = TitleScene() end
}
function TrainingScene:new()
menuKey = BUTTON.new{
text = "MENU",
x = 265, y = 0, w = 60, h = 25,
codeWhenReleased = function() SCENE = TitleScene() end
}
BUTTON.reset{menuKey}
VCTRL[9].show = true
game_mode = require 'game.gamemode'
if PENTO_MODE then

View File

@@ -10,12 +10,12 @@ local _defaultSettings = {
lines = true,
---@class input
---@field keys table <string, string>
---@field joysticks table <string, string>
---@field keys table <string, string>|nil
---@field joysticks table <string, string>|nil
---@field touch table <string, string>
input = {
keys = {},
joysticks = {},
keys = nil,
joysticks = nil,
virtual = {
{type='button',x= 70,y=280,key= 'up',r=45,iconSize=60,alpha=0.4},
{type='button',x= 70,y=430,key= 'down',r=45,iconSize=60,alpha=0.4},
@@ -28,7 +28,7 @@ local _defaultSettings = {
{type='button',x=320, y=420,key= 'restart',r=35,iconSize=60,alpha=0.4},
}
},
tvMode = false -- 79338732
tvMode = false
}
SETTINGS = setmetatable(