25 Commits

Author SHA1 Message Date
SweetSea
1c6857bca9 Fix longlasting wrong icon key 2024-11-24 15:40:16 +07:00
SweetSea
0e8d3ceacc Merge https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile 2024-10-27 05:58:03 +07:00
SweetSea
b73c82c765 Fix scene stack and bump ver 2024-10-27 05:56:40 +07:00
SweetSea-ButImNotSweet
d7d9f77127 Fix buttons in replay scene broken
Signed-off-by: SweetSea-ButImNotSweet <sweetsea-butimnotsweet@noreply.gitea.com>
2024-10-06 12:17:44 +00:00
Nguyễn Quốc Hưng
c0089fc4a5 Multiple changes
- Fix softlock in Name entry
- Wrong page count in Replay scene
- Last key can't be ignored by other controllers
- Small B.T.S changes
2024-10-06 16:57:49 +07:00
Nguyễn Quốc Hưng
1f5a21fec4 Cleaning stuffs 2024-08-17 16:11:42 +07:00
Nguyễn Quốc Hưng
628cf22110 Add user management scene 2024-08-17 16:10:52 +07:00
Nguyễn Quốc Hưng
0647babc90 Fix player's info is not updated correctly when changing name 2024-08-16 09:06:43 +07:00
Nguyễn Quốc Hưng
c29b97cece Fix wrong saving bind place 2024-08-11 10:12:57 +07:00
Nguyễn Quốc Hưng
78501f368c Update both key and stick configuration scenes 2024-08-10 17:13:43 +07:00
Nguyễn Quốc Hưng
e6388c79bc Attempt to fix, one again 2024-08-10 16:53:49 +07:00
Nguyễn Quốc Hưng
e4e43ec61e Fix dumb error 2024-08-10 14:45:22 +07:00
Nguyễn Quốc Hưng
0eb274436e Attempt to fix broken button 2024-08-10 14:34:08 +07:00
Nguyễn Quốc Hưng
f691f9e75d Bump version number 2024-08-10 08:00:15 +07:00
Nguyễn Quốc Hưng
e7474aefeb Reset background color 2024-08-10 07:55:22 +07:00
Nguyễn Quốc Hưng
c0d061e254 Update README 2024-08-10 07:52:14 +07:00
Nguyễn Quốc Hưng
c24cfe1a8b Small changes 2024-08-10 06:35:52 +07:00
SweetSea
3827304fc5 Fix gamepad system on Android
(tụi này không dùng cảm biến trọng trường đâu!)
2024-08-10 06:28:15 +07:00
Nguyễn Quốc Hưng
91100883fe Add buttons to prevent soft-lock in keybind conf. 2024-08-09 23:40:07 +07:00
Nguyễn Quốc Hưng
1a99de7435 Using Lily to speed up assets loading 2024-08-09 19:47:04 +07:00
Nguyễn Quốc Hưng
0a5bc1476d Attempt to fix soft lock in stick conf. screen 2024-08-09 10:45:48 +07:00
Squishy (C6H12O6+NaCl+H2O)
52f0e5323f Fix various bugs
- Sometimes keyboard suddenly closed while a key is being pressed on mobile (TEST)
- Fix navigation issue in replay scene
- Fix Confirm key is not usable as Restart in 20G Training
2024-06-14 15:20:36 +07:00
Squishy (C6H12O6+NaCl+H2O)
a5b72ef286 Disable OSK when starting game 2024-06-13 11:41:45 +07:00
Squishy (C6H12O6+NaCl+H2O)
a0575bdfab Erase outdated screenshots 2024-06-13 11:39:47 +07:00
Squishy (C6H12O6+NaCl+H2O)
0a2fd20075 Update replay screen 2024-06-13 11:38:17 +07:00
25 changed files with 1545 additions and 237 deletions

View File

@@ -3,7 +3,7 @@ A old-fashioned but modern block-stacking game. Made with :heart: by [mycophobia
Ported to Android (mobile and TV) by SweetSea with on-screen control (with some necessary changes) Ported to Android (mobile and TV) by SweetSea with on-screen control (with some necessary changes)
# How to play # How to play
> :warning: There is no Android build (aka APK file) right now. If you see any pre-built APK files on the internet. Please be aware > :warning: There is no Android build (aka APK file) right now. If you see any pre-built APK files on the internet. Please be aware of viruses and malwares
## For mobile ## For mobile
### Install ### Install
1. In the [Releases tab](https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/releases) and click on ``Source code (zip)`` 1. In the [Releases tab](https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/releases) and click on ``Source code (zip)``
@@ -15,8 +15,8 @@ Ported to Android (mobile and TV) by SweetSea with on-screen control (with some
7. Now, press Home (or back to app launcher), you can see two icons: ``LÖVE for Android`` and ``LÖVE Launcher``. You should use the ``LÖVE Launcher`` to launch Tromi 7. Now, press Home (or back to app launcher), you can see two icons: ``LÖVE for Android`` and ``LÖVE Launcher``. You should use the ``LÖVE Launcher`` to launch Tromi
### Launch ### Launch
1. Launch ``LÖVE Launcher``, an file picker will appear 1. Launch ``LÖVE Launcher``, an file picker will appear
2. Navigate to where you put the game file, example ``tromi_mobile.love`` 2. Navigate to where you put the file and pick Tromi
3. Pick the file and enjoy 3. Pick the file and enjoy.
## For TV ## For TV
> :warning: Before I tell you how, I need to tell you something > :warning: Before I tell you how, I need to tell you something
@@ -28,7 +28,7 @@ Ported to Android (mobile and TV) by SweetSea with on-screen control (with some
2. Install this file manager on your TV: https://play.google.com/store/apps/details?id=com.alphainventor.filemanager. Once you installed, you should see [this icon](https://play-lh.googleusercontent.com/9PzlG2XGr5sQDf5925tlZhqluOreI2cwzp-FOZiuj545Kt1Gk5EE9J4IdGsD7e5xWw=w240-h480-rw) 2. Install this file manager on your TV: https://play.google.com/store/apps/details?id=com.alphainventor.filemanager. Once you installed, you should see [this icon](https://play-lh.googleusercontent.com/9PzlG2XGr5sQDf5925tlZhqluOreI2cwzp-FOZiuj545Kt1Gk5EE9J4IdGsD7e5xWw=w240-h480-rw)
3. Opening the application, click on ``Access from...`` (network/other devices/etc.) 3. Opening the application, click on ``Access from...`` (network/other devices/etc.)
4. Transfer 2 downloaded files to TV 4. Transfer 2 downloaded files to TV
5. Install LÖVE for Android application (see step 6 in ``Install for TV`` section) 5. Install LÖVE for Android application (see step 6 in ``Install for mobile`` section)
6. *(First time only)* Open the ``tromi_mobile.love``. When the file manager asks you to open the file as what. Select ``Other``, then select ``LÖVE for Android`` and select ``Always`` 6. *(First time only)* Open the ``tromi_mobile.love``. When the file manager asks you to open the file as what. Select ``Other``, then select ``LÖVE for Android`` and select ``Always``
7. Once you are in the key configuration scene, type ``88663366``. An predefined keybind will be set automatically, but you can now make a different one if you'd like to 7. Once you are in the key configuration scene, type ``88663366``. An predefined keybind will be set automatically, but you can now make a different one if you'd like to
@@ -52,18 +52,19 @@ Navigate to where you put ``tromi_mobile.love`` in the File manager (the one you
* Update ``binser`` library, this fixes some weird bugs related to saving * Update ``binser`` library, this fixes some weird bugs related to saving
* Add ``simple-button`` module, made by me (SweetSea) * 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". * Replaced old Cambridge's ``config`` module with the new one inspired by "the sequel of Techmino"s ``SETTINGS`` module".
* Using `lily` to improve the loading speed of animated backgrounds and sounds.
# TODO # TODO
- [x] 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] 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) - [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)
- [x] Updating on-screen control configuration screen - [x] Updating on-screen control configuration screen
- [x] (Low priority) Design a new menu screen - [x] (Low priority) Design a new menu screen
- [x] Add shortcut to open replay converter at https://sweetsea-butimnotsweet.github.io/tromi_replay_converter
- [x] Redesign the replay selector screen
- [ ] Add user data management - [ ] Add user data management
- [ ] Redesign "the Control method selection" screen - [ ] 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) # License (GNU GPLv3)
Please read ``COPYING.txt`` for more information.<br> Please read ``COPYING.txt`` for more information.<br>
@@ -82,7 +83,7 @@ A small note about the music:
# Don't forget to check # Don't forget to check
* [Original Tromi](https://mycophobia.org/tromi) * [Original Tromi](https://mycophobia.org/tromi)
* [Leaderboard](https://mycophobia.org/) * [Leaderboard](https://mycophobia.org/forums/viewtopic.php?t=29)
* [Cambridge](https://github.com/Cambridge-stacker/Cambridge) * [Cambridge](https://github.com/Cambridge-stacker/Cambridge)
* [Techmino](https://github.com/26F-Studio/Techmino) * [Techmino](https://github.com/26F-Studio/Techmino)

View File

@@ -9,5 +9,5 @@ function love.conf(t)
t.window.height = 960 t.window.height = 960
t.window.vsync = false t.window.vsync = false
t.accelerometerjoystick = true t.accelerometerjoystick = false
end end

View File

@@ -11,8 +11,7 @@ local Randomizer = require 'game.randomizer'
local GameMode = Object:extend() local GameMode = Object:extend()
function GameMode:new(player_name, input_file, replay_grade) 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() VCTRL.reset()
if player_name == nil then self.training = true else self.training = false end if player_name == nil then self.training = true else self.training = false end

View File

@@ -15,7 +15,6 @@ local function mDrawQ(obj,quad,x,y,a,k)
love.graphics.draw(obj,quad,x,y,a,k,nil,w*.5,h*.5) love.graphics.draw(obj,quad,x,y,a,k,nil,w*.5,h*.5)
end end
ShowLoadingText('virtual key skin')
local empty_quad local empty_quad
-- A table containing quads used to draw icons for virtual control system. -- A table containing quads used to draw icons for virtual control system.
-- local virtual_quad=setmetatable((function() -- local virtual_quad=setmetatable((function()
@@ -42,7 +41,7 @@ local virtual_quad=setmetatable((function()
empty_quad=gc_newQuad(0,0,1,1,5*w,2*w) empty_quad=gc_newQuad(0,0,1,1,5*w,2*w)
for i,name in next,{ for i,name in next,{
'left','right','up','down','restart', 'left','right','up','down','restart',
'rotate_right','rotate_left','rotate_right2','rotate_left2','', 'rotate_left','rotate_right','rotate_left2','rotate_right2'
} do if #name>0 then t[name]=gc_newQuad((i-1)%5*w,math.floor((i-1)/5)*w,w,w,5*w,2*w) end end } do if #name>0 then t[name]=gc_newQuad((i-1)%5*w,math.floor((i-1)/5)*w,w,w,5*w,2*w) end end
return t return t
end)(),{ end)(),{
@@ -109,7 +108,7 @@ function control_type.button:draw(forceAlpha)
if self.shape=='circle' then if self.shape=='circle' then
love.graphics.setColor(0,0,0,alpha) love.graphics.setColor(0,0,0,alpha)
love.graphics.circle('fill',self.x,self.y,self.r-4) love.graphics.circle('fill',self.x,self.y,self.r-4)
love.graphics.setColor(1,1,1,self.pressed and .5 or 0) love.graphics.setColor(1,1,1,self.pressed and .5 or 0)
love.graphics.circle('fill',self.x,self.y,self.r-4) love.graphics.circle('fill',self.x,self.y,self.r-4)
@@ -118,7 +117,7 @@ function control_type.button:draw(forceAlpha)
elseif self.shape=='square' then elseif self.shape=='square' then
love.graphics.setColor(0,0,0,alpha) love.graphics.setColor(0,0,0,alpha)
love.graphics.rectangle('fill',self.x-self.r-4,self.y-self.r-4,self.r*2+8,self.r*2+8) love.graphics.rectangle('fill',self.x-self.r-4,self.y-self.r-4,self.r*2+8,self.r*2+8)
love.graphics.setColor(1,1,1,self.pressed and .5 or 0) love.graphics.setColor(1,1,1,self.pressed and .5 or 0)
love.graphics.rectangle('fill',self.x-self.r-4,self.y-self.r-4,self.r*2+8,self.r*2+8) love.graphics.rectangle('fill',self.x-self.r-4,self.y-self.r-4,self.r*2+8,self.r*2+8)
@@ -183,7 +182,7 @@ function VCTRL.clearAll()
local toggle = global_toggle local toggle = global_toggle
VCTRL.toggle(false) VCTRL.toggle(false)
global_toggle = toggle global_toggle = toggle
for i=#VCTRL,1,-1 do VCTRL[i] = nil end for i=#VCTRL,1,-1 do VCTRL[i] = nil end
collectgarbage() collectgarbage()
end end

1009
libs/lily.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -151,13 +151,13 @@ function button:press(x, y, touchID)
end end
---Trigger release action, don't need ``self._hovering`` to ``true`` ---Trigger release action, don't need ``self._hovering`` to ``true``
function button:release(x, y, touchID) function button:release(x, y, touchID)
local valid = true local valid
if touchID then if touchID then
valid = touchID == self._touchID valid = touchID == self._touchID
else else
valid = true valid = true
end end
if valid then if valid then
self._pressed = false self._pressed = false
self._touchID = false self._touchID = false
@@ -187,7 +187,7 @@ function BUTTON.checkDataValidation(D, safe)
elseif type(D.text) ~= 'string' then elseif type(D.text) ~= 'string' then
error("[text] must be a string or a function returns string, got "..type(D.text)) error("[text] must be a string or a function returns string, got "..type(D.text))
end end
assert(type(D.x) == "number" , "[x] must be a integer") assert(type(D.x) == "number" , "[x] must be a integer")
assert(type(D.y) == "number" , "[y] must be a integer") assert(type(D.y) == "number" , "[y] must be a integer")
assert(type(D.w) == "number" and D.w > 0, "[w] must be a positive integer") assert(type(D.w) == "number" and D.w > 0, "[w] must be a positive integer")

View File

@@ -60,22 +60,25 @@ BUTTON.setDefaultOption{
} }
-- Graphics -- Graphics
ShowLoadingText('backgrounds')
local gc_newImage, gc_newVideo = love.graphics.newImage, love.graphics.newVideo local gc_newImage, gc_newVideo = love.graphics.newImage, love.graphics.newVideo
BACKGROUNDS = { BACKGROUNDS = {}
[0] = gc_newVideo("res/backgrounds/green_waterfall.ogv", {audio=false}), LILY.loadMulti{
gc_newVideo("res/backgrounds/water.ogv", {audio=false}), {'newVideo', "res/backgrounds/green_waterfall.ogv", {audio=false}},
gc_newVideo("res/backgrounds/green_streams.ogv", {audio=false}), {'newVideo', "res/backgrounds/water.ogv", {audio=false}},
gc_newVideo("res/backgrounds/streams.ogv", {audio=false}), {'newVideo', "res/backgrounds/green_streams.ogv", {audio=false}},
gc_newVideo("res/backgrounds/red_forest_waterfall.ogv", {audio=false}), {'newVideo', "res/backgrounds/streams.ogv", {audio=false}},
gc_newVideo("res/backgrounds/flowers_rain.ogv", {audio=false}), {'newVideo', "res/backgrounds/red_forest_waterfall.ogv", {audio=false}},
gc_newVideo("res/backgrounds/moonlight_tree.ogv", {audio=false}), {'newVideo', "res/backgrounds/flowers_rain.ogv", {audio=false}},
gc_newVideo("res/backgrounds/lisa_frank.ogv", {audio=false}), {'newVideo', "res/backgrounds/moonlight_tree.ogv", {audio=false}},
gc_newVideo("res/backgrounds/snowy_trees.ogv", {audio=false}), {'newVideo', "res/backgrounds/lisa_frank.ogv", {audio=false}},
gc_newVideo("res/backgrounds/snowy_cabin.ogv", {audio=false}), {'newVideo', "res/backgrounds/snowy_trees.ogv", {audio=false}},
} {'newVideo', "res/backgrounds/snowy_cabin.ogv", {audio=false}},
}:onComplete(
function(_, lilies)
for i = 0, 9 do BACKGROUNDS[i] = lilies[i + 1][1] end
LOADED_BACKGROUND = true;
end)
ShowLoadingText('blocks')
BLOCKS = { BLOCKS = {
["2tie"] = { ["2tie"] = {
R = gc_newImage("res/img/r.png"), R = gc_newImage("res/img/r.png"),
@@ -112,21 +115,30 @@ COLOUR_SCHEMES = {
} }
-- BGMs and SFXs -- BGMs and SFXs
ShowLoadingText('BGMs & SFXs')
local audio_newSource = love.audio.newSource local audio_newSource = love.audio.newSource
SOUNDS = { SOUNDS = {}
bottom = audio_newSource("res/se/bottom.wav", "static"), LILY.loadMulti{
lock = audio_newSource("res/se/lock.wav", "static"), {"newSource", "res/se/bottom.wav", "static"},
erase = audio_newSource("res/se/erase.wav", "static"), {"newSource", "res/se/lock.wav", "static"},
fall = audio_newSource("res/se/fall.wav", "static"), {"newSource", "res/se/erase.wav", "static"},
ready = audio_newSource("res/se/ready.wav", "static"), {"newSource", "res/se/fall.wav", "static"},
promote = audio_newSource("res/se/promote.wav", "static"), {"newSource", "res/se/ready.wav", "static"},
demote = audio_newSource("res/se/demote.wav", "static"), {"newSource", "res/se/promote.wav", "static"},
autopromote = audio_newSource("res/se/autopromote.wav", "static"), {"newSource", "res/se/demote.wav", "static"},
bgm_firsthalf = audio_newSource("res/bgm/firsthalf.flac", "static"), {"newSource", "res/se/autopromote.wav", "static"},
bgm_secondhalf = audio_newSource("res/bgm/secondhalf.flac", "static"), {"newSource", "res/bgm/firsthalf.flac", "static"},
bgm_title = audio_newSource("res/bgm/title.flac", "static") {"newSource", "res/bgm/secondhalf.flac", "static"},
} {"newSource", "res/bgm/title.flac", "static"},
}:onComplete(
function(_, lilies)
SOUNDS.bottom, SOUNDS.lock, SOUNDS.erase, SOUNDS.fall = unpack(lilies, 1, 4)
SOUNDS.ready, SOUNDS.promote, SOUNDS.demote, SOUNDS.autopromote = unpack(lilies, 5, 8)
SOUNDS.bgm_firsthalf, SOUNDS.bgm_secondhalf, SOUNDS.bgm_title = unpack(lilies, 9)
for k, v in pairs(SOUNDS) do SOUNDS[k] = v[1] end -- Again, to avoid userdata
LOADED_MUSIC = true;
end
)
function PlaySE(sound, subsound) function PlaySE(sound, subsound)
if sound ~= nil then if sound ~= nil then

View File

@@ -12,26 +12,13 @@ if not love.filesystem.getInfo(REPLAY_DIR) then
love.filesystem.createDirectory(REPLAY_DIR) love.filesystem.createDirectory(REPLAY_DIR)
end end
BACKGROUND_COLOR = {32/255, 120/255, 88/255} BACKGROUND_COLOR = {0, 0, 0}
-- BACKGROUND_COLOR = {32/255, 120/255, 88/255}
CURRENT_OS = love.system.getOS() CURRENT_OS = love.system.getOS()
MOBILE = CURRENT_OS == "Android" or CURRENT_OS == "iOS" MOBILE = CURRENT_OS == "Android" or CURRENT_OS == "iOS"
LOADING_IMAGE_FILE = love.graphics.newImage('res/loading.png') LILY = require "libs.lily"
--- Show the loading text while we are loading resources<br>
--- **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() function love.load()
require 'funcs' require 'funcs'
@@ -53,17 +40,7 @@ function love.load()
require "game.vctrl" -- VCTRL require "game.vctrl" -- VCTRL
SCENE = LoadingScene() SCENE = LoadingScene()
sceneStack = {SCENE}
-- 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) VCTRL.new(SETTINGS.input.virtual)
end end
@@ -148,7 +125,6 @@ function love.keypressed(key, scancode)
love.resize(love.graphics.getDimensions()) love.resize(love.graphics.getDimensions())
elseif scancode == "f2" and SCENE.title ~= "Input Config" and SCENE.title ~= "Game" then elseif scancode == "f2" and SCENE.title ~= "Input Config" and SCENE.title ~= "Game" then
SCENE = InputConfigScene() SCENE = InputConfigScene()
elseif scancode == "f3" then SCENE = DataManagementScene()
elseif scancode == "f12" then LLDEBUGGER.requestBreak() elseif scancode == "f12" then LLDEBUGGER.requestBreak()
-- elseif scancode == "f11" then SETTINGS.firstTime = true -- elseif scancode == "f11" then SETTINGS.firstTime = true
-- function keys are reserved -- function keys are reserved
@@ -305,6 +281,10 @@ end
function love.focus(f) end function love.focus(f) end
function love.quit()
LILY.quit()
end
local TARGET_FPS = 60 local TARGET_FPS = 60
function love.run() function love.run()
@@ -329,6 +309,7 @@ function love.run()
end end
end end
if SCENE and SCENE.update and love.timer then if SCENE and SCENE.update and love.timer then
SCENE:update() SCENE:update()
@@ -433,7 +414,7 @@ function love.errorhandler(msg)
love.graphics.setColor(1, 1, 1) love.graphics.setColor(1, 1, 1)
love.graphics.draw(screenshot_canva, 0, 0, 0, screenshot_canva_scale) love.graphics.draw(screenshot_canva, 0, 0, 0, screenshot_canva_scale)
if not showScreenshot then if not showScreenshot then
love.graphics.setColor(0, 0, 0, 0.75) love.graphics.setColor(0, 0, 0, 0.75)
love.graphics.rectangle("fill", 0, 0, 640, 480) love.graphics.rectangle("fill", 0, 0, 640, 480)
@@ -589,6 +570,5 @@ function MainBackground()
while main_bg_cur_color == main_bg_last_color do main_bg_cur_color = minos[love.math.random(1,7)] end 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 main_bg_cur_mino = 1
end end
main_bg_placed = false
main_bg_draw_frame = main_bg_draw_frame + 1 main_bg_draw_frame = main_bg_draw_frame + 1
end end

View File

@@ -1,55 +0,0 @@
local Object = require "libs.classic"
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? string # Action triggered<br>Only visible via keyboard and gamepad
---@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
GameScene = require "scene.game"
TrainingScene = require "scene.training"
NameEntryScene = require "scene.name_entry"
KeyConfigScene = require "scene.key_config"
StickConfigScene = require "scene.stick_config"
TouchConfigScene = require "scene.touch_config"
TouchConfigPreviewScene = require "scene.touch_config_preview"
InputConfigScene = require "scene.input_config"
ReplaySelectScene = require "scene.replay"
ReplayTestScene = require"scene.replay_test"
FullscreenScene = require "scene.fullscreen"
MusicToggleScene = require "scene.music_toggle"
LinesToggleScene = require "scene.lines_toggle"
ExitScene = require "scene.exit"
TitleScene = require "scene.title"

View File

@@ -76,6 +76,7 @@ SettingsScene = require "scene.settings"
EraseHighScoresScene = require "scene.data.erase_high_scores" EraseHighScoresScene = require "scene.data.erase_high_scores"
ResetAllScene = require "scene.data.reset_all" ResetAllScene = require "scene.data.reset_all"
DataManagementScene = require "scene.data_management" DataManagementScene = require "scene.data_management"
UserManagementScene = require "scene.user_management"
ReplaySelectScene = require "scene.replay" ReplaySelectScene = require "scene.replay"
ReplayTestScene = require"scene.replay_test" ReplayTestScene = require"scene.replay_test"

View File

@@ -26,7 +26,7 @@ local data_explaination = {
local NULL = function() end local NULL = function() end
local settings_func = { local settings_func = {
function() love.system.openURL(love.filesystem.getSaveDirectory()) end, function() love.system.openURL(love.filesystem.getSaveDirectory()) end,
NULL, function() return UserManagementScene() end,
function() return EraseHighScoresScene() end, function() return EraseHighScoresScene() end,
function() return ResetAllScene() end, function() return ResetAllScene() end,
function() return TitleScene() end, function() return TitleScene() end,

View File

@@ -71,7 +71,7 @@ function ConfigScene:new(first_time)
secret_code_used = false secret_code_used = false
secret_code_input = {} -- When it matches 88663366 then we will automatically set the special keybind secret_code_input = {} -- When it matches 88663366 then we will automatically set the special keybind
self.menu_state = 1 self.menu_state = 1
if first_time then if first_time then
self.first_time = true self.first_time = true
@@ -84,15 +84,18 @@ function ConfigScene:update() end
function ConfigScene:render() function ConfigScene:render()
MainBackground() MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 0, 0, 640, 480)
if secret_code_used then if secret_code_used then
if SETTINGS.tvMode then if SETTINGS.tvMode then
drawText("TV mode is ON now! Check keybind below", 80, 40, 1000) drawText("TV mode is ON now! Check keybind below", 80, 40, 1000)
drawText("Which controls do you want to configure?", 80, 70, 1000) drawText("Which controls do you want to configure?", 80, 70, 1000)
drawText( drawText(
"2 - Up 1 - Rotate left 5 - Confirm selection\n".. "2 - Up 1 - Rotate left 5 - Confirm selection\n"..
"8 - Right 3 - Rotate right 0 - Back\n".. "8 - Down 3 - Rotate right 0 - Back\n"..
"4 - Left 7 - Rotate left 2\n".. "4 - Left 7 - Rotate left 2\n"..
"6 - Down 9 - Rotate right 2", 80, 350, 1000 "6 - Right 9 - Rotate right 2", 80, 350, 1000
) )
else else
drawText("TV mode is OFF now!", 80, 40, 1000) drawText("TV mode is OFF now!", 80, 40, 1000)
@@ -132,7 +135,7 @@ local function checkSecretCodeInput(key)
if secret_code_used then return end if secret_code_used then return end
if key:sub(1, 2) == "kp" then if key:sub(1, 2) == "kp" then
table.insert(secret_code_input, key:sub(3,3)) table.insert(secret_code_input, key:sub(3,3))
elseif key:find("[0-9.]") == 1 then elseif key:find("[0-9]") == 1 then
table.insert(secret_code_input, key) table.insert(secret_code_input, key)
else else
secret_code_input = {} -- Reset secret_code_input = {} -- Reset
@@ -146,14 +149,14 @@ local function checkSecretCodeInput(key)
if current_code == "88663366" then --TVMODEON if current_code == "88663366" then --TVMODEON
-- Set keybind -- Set keybind
SETTINGS.input.keys = { SETTINGS.input.keys = {
["2"] = "up", ["kp2"] = "up", ["2"] = "up", ["kp8"] = "up",
["8"] = "down", ["kp8"] = "down", ["8"] = "down", ["kp2"] = "down",
["4"] = "left", ["kp4"] = "left", ["4"] = "left", ["kp4"] = "left",
["6"] = "right", ["kp6"] = "right", ["6"] = "right", ["kp6"] = "right",
["1"] = "rotate_left", ["kp1"] = "rotate_left", ["1"] = "rotate_left", ["kp7"] = "rotate_left",
["3"] = "rotate_right", ["kp3"] = "rotate_right", ["3"] = "rotate_right", ["kp9"] = "rotate_right",
["7"] = "rotate_left2", ["kp7"] = "rotate_left2", ["7"] = "rotate_left2", ["kp1"] = "rotate_left2",
["9"] = "rotate_right2", ["kp9"] = "rotate_right2", ["9"] = "rotate_right2", ["kp3"] = "rotate_right2",
["5"] = "menu_decide", ["kp5"] = "menu_decide", ["5"] = "menu_decide", ["kp5"] = "menu_decide",
["0"] = "menu_back", ["kp0"] = "menu_back", ["0"] = "menu_back", ["kp0"] = "menu_back",
} }
@@ -161,7 +164,7 @@ local function checkSecretCodeInput(key)
SETTINGS.tvMode = true SETTINGS.tvMode = true
secret_code_used = true secret_code_used = true
updateButtonList(SCENE) updateButtonList(SCENE)
elseif current_code == "........" then elseif current_code == "11111111" then
SETTINGS.input.keys = {} SETTINGS.input.keys = {}
SETTINGS.tvMode = false SETTINGS.tvMode = false
secret_code_used = true secret_code_used = true

View File

@@ -1,5 +1,6 @@
local KeyConfigScene = SCENE:extend() local KeyConfigScene = SCENE:extend()
KeyConfigScene.title = "Key Config" KeyConfigScene.title = "Key Config"
local buttonList = {}
local configurable_inputs = { local configurable_inputs = {
"menu_decide", "menu_decide",
@@ -13,7 +14,6 @@ local configurable_inputs = {
"rotate_right", "rotate_right",
"rotate_right2", "rotate_right2",
} }
local input_names = { local input_names = {
menu_decide='Confirm Selection', menu_decide='Confirm Selection',
menu_back = 'Go Back', menu_back = 'Go Back',
@@ -27,7 +27,6 @@ local input_names = {
rotate_right2='Rotate Clockwise (2)' rotate_right2='Rotate Clockwise (2)'
} }
local function newSetInputs() local function newSetInputs()
local set_inputs = {} local set_inputs = {}
for i, input in ipairs(configurable_inputs) do for i, input in ipairs(configurable_inputs) do
@@ -40,6 +39,31 @@ function KeyConfigScene:new()
self.input_state = 1 self.input_state = 1
self.set_inputs = newSetInputs() self.set_inputs = newSetInputs()
self.new_input = {} self.new_input = {}
self.axis_timer = 0
BUTTON.reset(buttonList)
buttonList = { -- Configuring
BUTTON.new{
text = CHAR.key.tab.."\nTab",
x = 40, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "tab"} end
},
BUTTON.new{
text = CHAR.key.enter_or_return.."\nEnter/Return",
x = 150, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "return"} end
},
BUTTON.new{
text = CHAR.key.del.."\nDelete",
x = 260, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "delete"} end
},
BUTTON.new{
text = CHAR.key.esc.."\nEscape",
x = 370, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end
},
}
end end
function KeyConfigScene:update() function KeyConfigScene:update()
@@ -47,6 +71,10 @@ end
function KeyConfigScene:render() function KeyConfigScene:render()
MainBackground() MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 0, 0, 640, 480)
BUTTON.draw(buttonList)
for i, input in ipairs(configurable_inputs) do for i, input in ipairs(configurable_inputs) do
drawText(input_names[input], 40, 60 + i * 20, 200, "left") drawText(input_names[input], 40, 60 + i * 20, 200, "left")
if self.set_inputs[input] then if self.set_inputs[input] then
@@ -54,15 +82,17 @@ function KeyConfigScene:render()
end end
end end
if self.input_state > #configurable_inputs then if self.input_state > #configurable_inputs then
drawText("Press Enter/Confirm Selection to confirm, delete/backspace to retry" .. (SETTINGS.input.keys and ", esc/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 else
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("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) drawText("Function keys (F1, F2, etc.), Escape, and Tab can't be changed", 0, 35,1000)
end end
end end
function KeyConfigScene:onInputPress(e) function KeyConfigScene:onInputPress(e)
if e.type == "key" then if e.type == "mouse" or e.type == "touch" then
BUTTON.press(buttonList, e.x, e.y, e.id)
elseif e.type == "key" then
-- function keys, escape, and tab are reserved and can't be remapped -- function keys, escape, and tab are reserved and can't be remapped
if e.scancode == "escape" or (self.input_state > #configurable_inputs and e.input == "menu_back") then if e.scancode == "escape" or (self.input_state > #configurable_inputs and e.input == "menu_back") then
SCENE = InputConfigScene(SETTINGS.firstTime) SCENE = InputConfigScene(SETTINGS.firstTime)
@@ -72,10 +102,7 @@ function KeyConfigScene:onInputPress(e)
SCENE = SETTINGS.firstTime and TitleScene() or InputConfigScene() SCENE = SETTINGS.firstTime and TitleScene() or InputConfigScene()
SETTINGS.firstTime = false SETTINGS.firstTime = false
elseif e.scancode == "delete" or e.scancode == "backspace" then elseif e.scancode == "delete" or e.scancode == "backspace" then
-- retry self:new() -- retry
self.input_state = 1
self.set_inputs = newSetInputs()
self.new_input = {}
end end
elseif e.scancode == "tab" then elseif e.scancode == "tab" then
self.set_inputs[configurable_inputs[self.input_state]] = "skipped" self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
@@ -86,10 +113,22 @@ function KeyConfigScene:onInputPress(e)
self.new_input[e.scancode] = configurable_inputs[self.input_state] self.new_input[e.scancode] = configurable_inputs[self.input_state]
self.input_state = self.input_state + 1 self.input_state = self.input_state + 1
end end
elseif self.input_state < #configurable_inputs then elseif self.input_state <= #configurable_inputs then
self.set_inputs[configurable_inputs[self.input_state]] = "skipped" self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
self.input_state = self.input_state + 1 self.input_state = self.input_state + 1
end end
end end
function KeyConfigScene:onInputRelease(e)
if e.type == "mouse" or e.type == "touch" then
BUTTON.release(buttonList, e.x, e.y, e.id)
end
end
function KeyConfigScene:onInputMove(e)
if e.type == "mouse" then
BUTTON.checkHovering(buttonList, e.x, e.y)
end
end
return KeyConfigScene return KeyConfigScene

View File

@@ -1,10 +1,21 @@
local LoadingScene = SCENE:extend() local LoadingScene = SCENE:extend()
local LoadingImageFile = love.graphics.newImage('res/loading.png')
function LoadingScene.update() function LoadingScene.update()
SCENE = SETTINGS.firstTime and InputConfigScene(true) or TitleScene() if LOADED_BACKGROUND and LOADED_MUSIC then
SCENE = SETTINGS.firstTime and InputConfigScene(true) or TitleScene()
LILY.quit()
end
end end
function LoadingScene.render() function LoadingScene.render()
love.graphics.draw(LOADING_IMAGE_FILE,0,0,0,0.5) love.graphics.draw(LoadingImageFile,0,0,0,0.5)
drawText(
("Background: %s\nMusic & SFX: %s"):format(
LOADED_BACKGROUND and "loaded" or "...",
LOADED_MUSIC and "loaded" or "..."
),
15, 400, 1e99, "left"
)
end end
return LoadingScene return LoadingScene

View File

@@ -37,12 +37,12 @@ local Grid = require 'game.grid'
function NameEntryScene:new() function NameEntryScene:new()
VCTRL.toggle(false) VCTRL.toggle(false)
self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890." self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890."
self.char_pos = 1 self.char_pos = 1
self.name_entry = {'A','A','A'} self.name_entry = {'A','A','A'}
self.entry_pos = 1 self.entry_pos = 1
self.entry_chars = self.name_entry[1]..self.name_entry[2]..self.name_entry[3] self.entry_chars = table.concat(self.name_entry, '', 1, 3)
self.grid = Grid(10, 20) self.grid = Grid(10, 20)
self.repeat_limit = 10 self.repeat_limit = 10
self.repeat_counter = self.repeat_limit-1 self.repeat_counter = self.repeat_limit-1
@@ -79,7 +79,7 @@ end
function NameEntryScene:render() function NameEntryScene:render()
MainBackground() MainBackground()
BUTTON.draw(buttonList) BUTTON.draw(buttonList)
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.line(216,80,216,80+(16*self.grid.height)) 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+(16*self.grid.width),80,216+(16*self.grid.width),80+(16*self.grid.height))
@@ -130,7 +130,7 @@ function NameEntryScene:update()
end end
self.repeat_counter = self.repeat_counter + 1 self.repeat_counter = self.repeat_counter + 1
end end
self.entry_chars = self.name_entry[1]..self.name_entry[2]..self.name_entry[3] self.entry_chars = table.concat(self.name_entry, '', 1, 3)
end end
function NameEntryScene:onInputMove(e) function NameEntryScene:onInputMove(e)
@@ -146,38 +146,24 @@ function NameEntryScene:getPlayInfo(player_name)
self.wins = grade_history[2] self.wins = grade_history[2]
self.plays = grade_history[4] self.plays = grade_history[4]
else else
self.grade, self.win, self.plays = 0, 0, 0 self.grade, self.wins, self.plays = 0, 0, 0
end end
return self.grade, self.win, self.plays
end end
function NameEntryScene:onInputPress(e) function NameEntryScene:onInputPress(e)
local name = string.lower(self.name_entry[1]..self.name_entry[2]..self.name_entry[3]) local name = string.lower(table.concat(self.name_entry, '', 1, 3))
if e.type == "mouse" or e.type == "touch" then if e.type == "mouse" or e.type == "touch" then
BUTTON.press(buttonList, e.x, e.y, e.id) 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 elseif e.input == "menu_decide" or e.input == "rotate_left" or e.scancode == "return" then
if self.entry_pos == 4 then if self.entry_pos == 4 then
BUTTON.release(buttonList, e.x, e.y, e.id) BUTTON.release(buttonList, e.x, e.y, e.id)
SETTINGS['last_entry'] = name:upper() SETTINGS['last_entry'] = name:upper()
SCENE = GameScene(name:lower()) SCENE = GameScene(name:lower())
else elseif self.entry_pos == 3 then self:getPlayInfo(name)
if self.entry_pos == 3 then self:getPlayInfo(name)
else else
self.name_entry[self.entry_pos ] = self.chars:sub(self.char_pos, self.char_pos) 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) self.name_entry[self.entry_pos+1] = self.chars:sub(self.char_pos, self.char_pos)
end end
self.entry_pos = self.entry_pos + 1 self.entry_pos = self.entry_pos + 1
end
elseif e.input == "left" or e.scancode == "left" then elseif e.input == "left" or e.scancode == "left" then
self.direction = "left" self.direction = "left"
elseif e.input == "right" or e.scancode == "right" then elseif e.input == "right" or e.scancode == "right" then
@@ -193,12 +179,27 @@ function NameEntryScene:onInputPress(e)
self.entry_pos = self.entry_pos - 1 self.entry_pos = self.entry_pos - 1
self.grade = 0 self.grade = 0
end end
elseif e.key and #e.key == 1 then
local pos = string.find(self.chars, 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
self.entry_pos = math.min(self.entry_pos + 1, 4)
if self.entry_pos == 4 then self:getPlayInfo(string.lower(table.concat(self.name_entry, '', 1, 3))) end
end
end end
end end
function NameEntryScene:onInputRelease(e) function NameEntryScene:onInputRelease(e)
if e.type == "mouse" or e.type == "touch" then if e.type == "mouse" or e.type == "touch" then
BUTTON.release(buttonList, e.x, e.y, e.id) BUTTON.release(buttonList, e.x, e.y, e.id)
elseif (
MOBILE and not SETTINGS.tvMode and
self.entry_pos == 4
) then love.keyboard.setTextInput(false)
elseif e.input == "left" or e.scancode == "left" or e.input == "right" or e.scancode == "right" then elseif e.input == "left" or e.scancode == "left" or e.input == "right" or e.scancode == "right" then
self.direction = nil self.direction = nil
self.repeat_counter = self.repeat_limit-1 self.repeat_counter = self.repeat_limit-1

View File

@@ -4,38 +4,41 @@ ReplaySelectScene.title = "Replay"
local replay_list local replay_list
local buttonList = { local buttonList = {
BUTTON.new{ BUTTON.new{
text = CHAR.key.up.."\nUP", font = FONT_big, x = 325, y = 375, w = 100, h = 30,
x = 425, y = 80, w = 80, h = 80, text = CHAR.key.up.." Page up",
codeWhenPressed = function() SCENE:onInputPress {input = "up"} end, codeWhenReleased = function() SCENE:onInputPress{input = "left"} end
codeWhenReleased = function() SCENE:onInputRelease{input = "up"} end
}, },
BUTTON.new{ BUTTON.new{
text = CHAR.key.down.."\nDOWN", font = FONT_big, x = 435, y = 375, w = 100, h = 30,
x = 425, y = 240, w = 80, h = 80, text = CHAR.key.down.." Page down",
codeWhenPressed = function() SCENE:onInputPress {input = "down"} end, codeWhenReleased = function() SCENE:onInputPress{input = "right"} end
codeWhenReleased = function() SCENE:onInputRelease{input = "down"} end
}, },
BUTTON.new{ BUTTON.new{
text = CHAR.icon.play.."\nPLAY", font = FONT_big, x = 105, y = 375, w = 100, h = 30,
x = 345, y = 160, w = 80, h = 80, text = CHAR.icon.play.." Play",
codeWhenPressed = function() SCENE:onInputPress {input = "menu_decide"} end, codeWhenPressed = function() SCENE:onInputPress {input = "menu_decide"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "menu_decide"} end codeWhenReleased = function() SCENE:onInputRelease{input = "menu_decide"} end
}, },
BUTTON.new{ BUTTON.new{
text = CHAR.icon.home.."\nHOME", font = FONT_big, x = 105, y = 415, w = 100, h = 45,
x = 505, y = 160, w = 80, h = 80, text = CHAR.icon.home.." Home",
codeWhenPressed = function() SCENE:onInputPress {input = "menu_back"} end, codeWhenPressed = function() SCENE:onInputPress {input = "menu_back"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "menu_back"} end codeWhenReleased = function() SCENE:onInputRelease{input = "menu_back"} end
}, },
BUTTON.new{ BUTTON.new{
text = CHAR.icon.export.."\nEXP.", font = FONT_big, x = 215, y = 415, w = 100, h = 45,
x = 345, y = 320, w = 80, h = 80, text = CHAR.icon.save.." Converter",
codeWhenReleased = function() love.system.openURL("https://sweetsea-butimnotsweet.github.io/tromi_replay_converter/") end
},
BUTTON.new{
x = 325, y = 415, w = 100, h = 45,
text = CHAR.icon.export.." Export\n(R.Left)",
codeWhenPressed = function() SCENE:onInputPress {input = "rotate_left"} end, codeWhenPressed = function() SCENE:onInputPress {input = "rotate_left"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "rotate_left"} end codeWhenReleased = function() SCENE:onInputRelease{input = "rotate_left"} end
}, },
BUTTON.new{ BUTTON.new{
text = CHAR.icon.import.."\nIMP.", font = FONT_big, x = 435, y = 415, w = 100, h = 45,
x = 505, y = 320, w = 80, h = 80, text = CHAR.icon.import.." Import\n(R.Right)",
codeWhenPressed = function() SCENE:onInputPress {input = "rotate_right"} end, codeWhenPressed = function() SCENE:onInputPress {input = "rotate_right"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "rotate_right"} end codeWhenReleased = function() SCENE:onInputRelease{input = "rotate_right"} end
}, },
@@ -43,6 +46,8 @@ local buttonList = {
function ReplaySelectScene:new() function ReplaySelectScene:new()
self:initList() self:initList()
SCENE = self
BUTTON.reset(buttonList)
PENTO_MODE = false PENTO_MODE = false
end end
@@ -51,7 +56,7 @@ function ReplaySelectScene:initList()
replay_list = love.filesystem.getDirectoryItems('saves/replays/') replay_list = love.filesystem.getDirectoryItems('saves/replays/')
table.sort(replay_list, function(a,b) return a > b end) table.sort(replay_list, function(a,b) return a > b end)
self.replay_text = {} self.replay_text = {}
self.page_flip = 16 self.page_flip = 10
self.page = 1 self.page = 1
local gradeNames = { local gradeNames = {
"19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k", "19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k",
@@ -81,29 +86,32 @@ end
function ReplaySelectScene:render() function ReplaySelectScene:render()
MainBackground() MainBackground()
love.graphics.setColor(0.4, 1, 1, 0.5) love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 0, 20 + 20 * self.replay_select, 640, 22) love.graphics.rectangle("fill", 0, 0, 640, 480)
BUTTON.draw(buttonList) if #self.replays > 0 then
love.graphics.setColor(0.4, 1, 1, 0.5)
love.graphics.rectangle("fill", 0, 15 + 30 * self.replay_select, 640, 27)
drawText('Name - Grade - Score', 40, 20, 1000, "left") drawText('Name - Grade - Score', 40, 20, 1000, "left")
drawText(string.format('Page %s/%s', self.page, math.floor(#self.replays / self.page_flip) + 1), 20, 440, 1000, "left") drawText(string.format('Page %s/%s', self.page, 1 + math.floor((#self.replays - 1) / self.page_flip)), 215, 380, 100, "center")
local i, j = 1, 1 local i, j = 1, 1
while i <= #self.replay_text do while i <= #self.replay_text do
if j > self.page_flip then j = 1 if j > self.page_flip then j = 1
elseif j < 1 then j = self.page_flip elseif j < 1 then j = self.page_flip
end
if i > (self.page-1) * self.page_flip and i <= self.page * self.page_flip then
drawText(self.replay_text[i], 40, 20 + 30 * j, 1000, "left")
end
j = j + 1
i = i + 1
end end
if i > (self.page-1) * self.page_flip and i <= self.page * self.page_flip then else
drawText(self.replay_text[i], 40, 20 + 20 * j, 1000, "left")
end
j = j + 1
i = i + 1
end
if self.replays[1] == nil then
drawText('No replays yet!', 40, 40, 1000, "left") drawText('No replays yet!', 40, 40, 1000, "left")
end end
BUTTON.draw(buttonList)
end end
function ReplaySelectScene:update() function ReplaySelectScene:update()
@@ -145,8 +153,19 @@ function ReplaySelectScene:onInputPress(e)
local selected_replay = self.replays[self.replay_select + ((self.page-1) * self.page_flip)] local selected_replay = self.replays[self.replay_select + ((self.page-1) * self.page_flip)]
local selected_replay_text = self.replay_text[self.replay_select + ((self.page-1) * self.page_flip)] local selected_replay_text = self.replay_text[self.replay_select + ((self.page-1) * self.page_flip)]
if e.type == "touch" or e.type == "mouse" then if (
BUTTON.press(buttonList, e.x, e.y, e.id) (e.type == "touch" or e.type == "mouse") and
not BUTTON.press(buttonList, e.x, e.y, e.id) and
#self.replays > 0
) then
local selection = math.floor((e.y - 15) / 30)
if (
selection >= 1 and
selection <= self.repeat_limit and
selection + ((self.page-1) * self.page_flip) <= #replay_list
) then
self.replay_select = selection
end
elseif e.input == "menu_decide" or e.scancode == "return" then elseif e.input == "menu_decide" or e.scancode == "return" then
if self.replays[1] == nil then SCENE = TitleScene(); return if self.replays[1] == nil then SCENE = TitleScene(); return
else else
@@ -183,6 +202,22 @@ function ReplaySelectScene:onInputPress(e)
elseif e.input == "down" or e.scancode == "down" then elseif e.input == "down" or e.scancode == "down" then
if self.replays[1] == nil then SCENE = TitleScene(); return end if self.replays[1] == nil then SCENE = TitleScene(); return end
self.direction = 'down' self.direction = 'down'
elseif e.input == "left" or e.scancode == "left" then
if self.replays[1] == nil then SCENE = TitleScene(); return end
if self.page == 1 then
self.page = math.floor((#self.replays - 1) / self.page_flip)
else
self.page = self.page - 1
end
self.replay_select = 1;
elseif e.input == "right" or e.scancode == "right" then
if self.replays[1] == nil then SCENE = TitleScene(); return end
if self.page < 1 + math.floor((#self.replays - 1) / self.page_flip) then
self.page = self.page + 1
else
self.page = 1
end
self.replay_select = 1;
elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then
SCENE = TitleScene() SCENE = TitleScene()
end end

View File

@@ -5,7 +5,6 @@ local error_message
local valid_data local valid_data
local prev_scene local prev_scene
function ReplayTestScene:new(input_file) function ReplayTestScene:new(input_file)
prev_scene = SCENE prev_scene = SCENE
@@ -36,7 +35,7 @@ function ReplayTestScene:render()
if valid_data then if valid_data then
if error_message then if error_message then
drawText("Replay test failed! Data corrupted!", 80, 40, 1000) drawText("Replay test failed!", 80, 40, 1000)
drawText("Press any key to go back. Anyway here is the error info:", 80, 70, 1000) drawText("Press any key to go back. Anyway here is the error info:", 80, 70, 1000)
drawText(error_message, 80, 100, 560) drawText(error_message, 80, 100, 560)
else else

View File

@@ -12,7 +12,7 @@ local settings_explaination = {
"Enable music?\nThis does not apply to sound effects.", "Enable music?\nThis does not apply to sound effects.",
"Show level and lines counter?\nThis setting is ignored when replaying.", "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.", "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", "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\t11111111 disable TV mode",
"Back to main menu" "Back to main menu"
} }

View File

@@ -1,5 +1,6 @@
local StickConfigScene = SCENE:extend() local StickConfigScene = SCENE:extend()
StickConfigScene.title = "Controller Config" StickConfigScene.title = "Controller Config"
local buttonList = {}
local configurable_inputs = { local configurable_inputs = {
"menu_decide", "menu_decide",
@@ -13,7 +14,6 @@ local configurable_inputs = {
"rotate_right", "rotate_right",
"rotate_right2", "rotate_right2",
} }
local input_names = { local input_names = {
menu_decide='Confirm Selection', menu_decide='Confirm Selection',
menu_back = 'Go Back', menu_back = 'Go Back',
@@ -40,6 +40,30 @@ function StickConfigScene:new()
self.set_inputs = newSetInputs() self.set_inputs = newSetInputs()
self.new_input = {} self.new_input = {}
self.axis_timer = 0 self.axis_timer = 0
BUTTON.reset(buttonList)
buttonList = { -- Configuring
BUTTON.new{
text = CHAR.key.tab.."\nTab",
x = 40, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "tab"} end
},
BUTTON.new{
text = CHAR.key.enter_or_return.."\nEnter/Return",
x = 150, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "return"} end
},
BUTTON.new{
text = CHAR.key.del.."\nDelete",
x = 260, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "delete"} end
},
BUTTON.new{
text = CHAR.key.esc.."\nEscape",
x = 370, y = 300, w = 100, h = 50,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end
},
}
end end
function StickConfigScene:update() function StickConfigScene:update()
@@ -47,6 +71,10 @@ end
function StickConfigScene:render() function StickConfigScene:render()
MainBackground() MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 0, 0, 640, 480)
BUTTON.draw(buttonList)
for i, input in ipairs(configurable_inputs) do for i, input in ipairs(configurable_inputs) do
drawText(input_names[input], 40, 60 + i * 20, 200, "left") drawText(input_names[input], 40, 60 + i * 20, 200, "left")
if self.set_inputs[input] then if self.set_inputs[input] then
@@ -54,7 +82,7 @@ function StickConfigScene:render()
end end
end end
if self.input_state > #configurable_inputs then if self.input_state > #configurable_inputs then
drawText("Press enter/Confirm Selection to confirm, delete/backspace to retry" .. (SETTINGS.input.joysticks and ", esc/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 else
drawText("Press joystick input for " .. input_names[configurable_inputs[self.input_state]] .. ", tab to skip, escape to cancel", 0, 0, 1000) drawText("Press joystick input for " .. input_names[configurable_inputs[self.input_state]] .. ", tab to skip, escape to cancel", 0, 0, 1000)
end end
@@ -69,22 +97,19 @@ local function addJoystick(input, name)
end end
function StickConfigScene:onInputPress(e) function StickConfigScene:onInputPress(e)
if e.type == "key" then if e.type == "mouse" or e.type == "touch" then
BUTTON.press(buttonList, e.x, e.y, e.id)
elseif e.type == "key" then
-- function keys, escape, and tab are reserved and can't be remapped -- function keys, escape, and tab are reserved and can't be remapped
if e.scancode == "escape" or (self.input_state > #configurable_inputs and e.input == "menu_back") then if e.scancode == "escape" or (self.input_state > #configurable_inputs and e.input == "menu_back") then
SCENE = InputConfigScene() SCENE = InputConfigScene(SETTINGS.firstTime)
elseif self.input_state > #configurable_inputs then elseif self.input_state > #configurable_inputs then
if e.scancode == "return" or e.input == "" then if e.scancode == "return" or e.input == "menu_decide" then
-- save new input, then load next scene
local had_config = SETTINGS.input ~= nil
if not SETTINGS.input then SETTINGS.input = {} end
SETTINGS.input.joysticks = self.new_input SETTINGS.input.joysticks = self.new_input
SCENE = had_config and InputConfigScene() or TitleScene() SCENE = SETTINGS.firstTime and TitleScene() or InputConfigScene()
SETTINGS.firstTime = false
elseif e.scancode == "delete" or e.scancode == "backspace" then elseif e.scancode == "delete" or e.scancode == "backspace" then
-- retry self:new() -- retry
self.input_state = 1
self.set_inputs = newSetInputs()
self.new_input = {}
end end
else -- Other keys - skip else -- Other keys - skip
self.set_inputs[configurable_inputs[self.input_state]] = "skipped" self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
@@ -149,4 +174,16 @@ function StickConfigScene:onInputPress(e)
end end
end end
function StickConfigScene:onInputRelease(e)
if e.type == "mouse" or e.type == "touch" then
BUTTON.release(buttonList, e.x, e.y, e.id)
end
end
function StickConfigScene:onInputMove(e)
if e.type == "mouse" then
BUTTON.checkHovering(buttonList, e.x, e.y)
end
end
return StickConfigScene return StickConfigScene

View File

@@ -25,7 +25,7 @@ local main_menu_scenes = {
DataManagementScene, DataManagementScene,
function() love.system.openURL("https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile") end, function() love.system.openURL("https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile") end,
AboutScene, AboutScene,
TrainingScene, TrainingScene,
function() love.system.openURL("https://mycophobia.org/forums/viewtopic.php?t=29") end, function() love.system.openURL("https://mycophobia.org/forums/viewtopic.php?t=29") end,
SettingsScene, SettingsScene,
@@ -39,7 +39,7 @@ local main_menu_icons = {
CHAR.icon.export, CHAR.icon.export,
CHAR.icon.home, CHAR.icon.home,
CHAR.icon.info, CHAR.icon.info,
CHAR.icon.toDown, CHAR.icon.toDown,
CHAR.icon.globe, CHAR.icon.globe,
CHAR.icon.settings, CHAR.icon.settings,
@@ -63,13 +63,13 @@ end
function Title2Scene:render() function Title2Scene:render()
MainBackground() MainBackground()
love.graphics.setColor(0, 0, 0, 0.7) love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 30, 60, 580, 85, 10, 10) -- Tromi love.graphics.rectangle("fill", 30, 60, 580, 85, 10, 10) -- Tromi
love.graphics.rectangle("fill", 30, 165, 580, 225, 10, 10) -- Menu love.graphics.rectangle("fill", 30, 165, 580, 225, 10, 10) -- Menu
drawBigText("Tromi", 40, 65, 100, "left") drawBigText("Tromi", 40, 65, 100, "left")
drawText("Mobile 1.0 - PC 2.3", 150, 78, 200, "left") drawText("Mobile 1.4 - PC 2.3", 150, 78, 200, "left")
drawText("https://mycophobia.org\nhttps://github.com/SweetSea-ButImNotSweet/", 40, 100, 300, "left") drawText("https://mycophobia.org\nhttps://github.com/SweetSea-ButImNotSweet/", 40, 100, 300, "left")
if PENTO_MODE then if PENTO_MODE then
@@ -109,7 +109,7 @@ local function checkCode(c)
if ( if (
code_string == "-1,-1,-1,-1,1,1,1,1" or code_string == "-1,-1,-1,-1,1,1,1,1" or
code_string == "2,2,2,2,2,2,2,2" code_string == "2,2,2,2,2,2,2,2"
) then ) then
PENTO_MODE = true PENTO_MODE = true
end end
end end

View File

@@ -54,7 +54,7 @@ end
function TrainingScene:onInputPress(e) function TrainingScene:onInputPress(e)
if e.type == "mouse" or (e.type == "touch" and not VCTRL.press(e.x, e.y, e.id)) then if e.type == "mouse" or (e.type == "touch" and not VCTRL.press(e.x, e.y, e.id)) then
menuKey:press(e.x, e.y, e.id) menuKey:press(e.x, e.y, e.id)
elseif (self.game.game_over or self.game.completed) and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "rotate_right") and self.game.game_over_frames > 50 then elseif (self.game.game_over or self.game.completed) and (e.input == "menu_back" or e.input == "rotate_right") and self.game.game_over_frames > 50 then
SCENE = TitleScene() SCENE = TitleScene()
elseif (e.input == "menu_back") then elseif (e.input == "menu_back") then
SCENE = TitleScene() SCENE = TitleScene()

237
scene/user_management.lua Normal file
View File

@@ -0,0 +1,237 @@
local UserManagementScene = SCENE:extend()
local max_items_per_page = 10
local gradeNames = {
"19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k",
"10k", " 9k", " 8k", " 7k", " 6k", " 5k", " 4k", " 3k", " 2k", " 1k",
" 1D", " 2D", " 3D", " 4D", " 5D", " 6D", " 7D", " 8D", " 9D"
}
local user_list
local buttonList = {
BUTTON.new{
text = CHAR.icon.home.." Home\nEsc/Go back",
x = 510, y = 45, w = 120, h = 55,
codeWhenPressed = function() SCENE = TitleScene() end
},
BUTTON.new{
text = CHAR.icon.trash.." Delete\nDel/Rotate right",
x = 510, y = 105, w = 120, h = 55,
codeWhenPressed = function() SCENE:onInputPress{key = "delete"} end
},
BUTTON.new{
text = CHAR.key.up.." Page up\nLeft",
x = 510, y = 165, w = 120, h = 55,
},
BUTTON.new{
text = CHAR.key.down.." Page down\nRight",
x = 510, y = 225, w = 120, h = 55,
}
}
function UserManagementScene:new()
user_list = {}
self.current_page = 1
self.direction = nil
self.selecting = 1
self.repeat_counter = max_items_per_page - 1
for _, f in pairs(love.filesystem.getDirectoryItems(SAVE_DIR)) do
local file = SAVE_DIR .. f
local info = love.filesystem.getInfo(file)
if info and info.type == "file" and string.sub(f, 4, -1) == "_grade_history.sav" then
local name = string.sub(f, 1, 3)
table.insert(user_list, {
name = name,
valid = false, -- Data is not broken?
grade = 1, -- Player's grade
promo = 2, -- Promotion Meter
games = 0, -- Games played
})
local okay, _ = pcall(function()
local data = FILE.read(file)
if not data then error() end
user_list[#user_list].grade = data[1]
user_list[#user_list].promo = data[2]
user_list[#user_list].games = data[4]
end)
if okay then
user_list[#user_list].valid = true
end
end
end
end
local function getPromotionText(grade, promotion)
local points_text
if grade == 1 then
points_text = ({
[2] = " |..",
[3] = " .|.",
[4] = " ..|",
})[promotion]
else
points_text = ({
[0] = "|....",
[1] = ".|...",
[2] = "..|..",
[3] = "...|.",
[4] = "....|",
})[promotion]
end
return (grade > 1 and "-" or " ")..points_text..(grade < 29 and "+" or "")
end
function UserManagementScene:changeOption(rel)
local len = #user_list
self.selecting = self.selecting + rel
if self.selecting + ((self.current_page-1) * max_items_per_page) > len then
self.current_page = 1
self.selecting = 1
elseif self.selecting < 1 and self.current_page == 1 then
self.current_page = 1 + (math.floor(len / max_items_per_page))
self.selecting = len - ((self.current_page - 1) * max_items_per_page)
end
if self.selecting > max_items_per_page then
self.current_page = self.current_page + 1
self.selecting = 1
elseif self.selecting < 1 then
self.current_page = self.current_page - 1
self.selecting = max_items_per_page
end
end
function UserManagementScene:deleteCurrentReplay()
local name = user_list[max_items_per_page * (self.current_page - 1) + self.selecting].name
if love.window.showMessageBox(
"Delete the selected profile?",
"Are you sure you want to delete " .. string.upper(name) .. "'s profile?",
{
"Delete", ">>>CANCEL<<<",
escapebutton = 2
},
"warning"
) == 1 then
if love.window.showMessageBox(
"Are you really sure???",
"You really want to erase " .. string.upper(name) .. "'s profile?????\nYou may REGRET your action. This is NOT INVERSIBLE!",
{
">>>CANCEL<<<", "Delete",
escapebutton = 1
},
"warning"
) == 2 then
love.filesystem.remove(SAVE_DIR .. name .. "_grade_history.sav")
self:new()
end
end
end
function UserManagementScene:render()
MainBackground()
love.graphics.setColor(0, 0, 0, 0.7)
love.graphics.rectangle("fill", 0, 0, 640, 480)
love.graphics.setColor(0.4, 1, 1, 0.5)
love.graphics.rectangle("fill", 0, 15 + 30 * self.selecting, 500, 27)
BUTTON.draw(buttonList)
drawText('Name - Grade - Pro.Meter - Games', 40, 20, 1000, "left")
-- SEA 19k -..|..+ 12345
for i = (self.current_page - 1) * max_items_per_page + 1, math.min((self.current_page) * max_items_per_page, #user_list) do
if user_list[i].valid then
local name = user_list[i].name
local games = string.format("%5d", user_list[i].games)
local grade = gradeNames[user_list[i].grade]
local promo = getPromotionText(user_list[i].grade, user_list[i].promo)
drawText(
" " ..
name .. " " ..
grade .. " " ..
promo .. " " ..
games,
40, 20 + 30 * (i - (self.current_page - 1) * max_items_per_page), 1000, "left"
)
else
drawText(
" " .. user_list[i].name.." ??? -?????+ ?????",
40, 20 + 30 * (i - (self.current_page - 1) * max_items_per_page), 1000, "left"
)
end
end
drawText(string.format('Page %s/%s', self.current_page, math.floor(#user_list / max_items_per_page) + 1), 15, 440, 100,
"center")
end
function UserManagementScene:update()
if self.direction == "up" then
if self.repeat_counter >= max_items_per_page then
self:changeOption(-1)
self.repeat_counter = 0
end
self.repeat_counter = self.repeat_counter + 1
elseif self.direction == "down" then
if self.repeat_counter >= max_items_per_page then
self:changeOption(1)
self.repeat_counter = 0
end
self.repeat_counter = self.repeat_counter + 1
end
end
---@param e SCENE_onInput
function UserManagementScene:onInputPress(e)
if e.type == "mouse" or e.type == "touch" then
if not BUTTON.press(buttonList, e.x, e.y, e.id) then
local selection = math.floor((e.y - 45) / 30) + 1
love.window.showMessageBox("", selection)
if (
selection >= 1 and
selection <= self.repeat_counter and
selection + ((self.current_page-1) * max_items_per_page) <= #user_list
) then
self.selecting = selection
end
end
elseif e.input == "menu_back" then SCENE = TitleScene()
elseif e.input == "up" or e.key == "up" then self.direction = "up"
elseif e.input == "down" or e.key == "down" then self.direction = "down"
elseif e.input == "left" or e.key == "left" then
if self.current_page == 1 then
self.current_page = 1 + math.floor(#user_list / max_items_per_page)
else
self.current_page = self.current_page - 1
end
self.selecting = 1
elseif e.input == "right" or e.key == "right" then
if self.current_page < 1 + math.floor(#user_list / max_items_per_page) then
self.current_page = self.current_page + 1
else
self.current_page = 1
end
self.selecting = 1
elseif e.input == "rotate_right" or e.key == "delete" then self:deleteCurrentReplay()
end
end
function UserManagementScene:onInputRelease(e)
if e.type == "mouse" or e.type == "touch" then
BUTTON.release(buttonList, e.x, e.y, e.id)
elseif e.input == "up" or e.scancode == "up" or e.input == "down" or e.scancode == "down" then
self.direction = nil
self.repeat_counter = max_items_per_page - 1
end
end
function UserManagementScene:onInputMove(e)
if e.type == "mouse" then
BUTTON.checkHovering(buttonList, e.x, e.y)
end
end
return UserManagementScene

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 KiB