12 Commits

Author SHA1 Message Date
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
18 changed files with 1269 additions and 135 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)
# 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
### Install
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
### Launch
1. Launch ``LÖVE Launcher``, an file picker will appear
2. Navigate to where you put the game file, example ``tromi_mobile.love``
3. Pick the file and enjoy
2. Navigate to where you put the file and pick Tromi
3. Pick the file and enjoy.
## For TV
> :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)
3. Opening the application, click on ``Access from...`` (network/other devices/etc.)
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``
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
* 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".
* Using `lily` to improve the loading speed of animated backgrounds and sounds.
# 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] 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] (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
- [ ] 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>
@@ -82,7 +83,7 @@ A small note about the music:
# Don't forget to check
* [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)
* [Techmino](https://github.com/26F-Studio/Techmino)

View File

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

View File

@@ -11,8 +11,7 @@ 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(true)
VCTRL.toggle(MOBILE and not input_file and not SETTINGS.tvMode)
VCTRL.reset()
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)
end
ShowLoadingText('virtual key skin')
local empty_quad
-- A table containing quads used to draw icons for virtual control system.
-- 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)
for i,name in next,{
'left','right','up','down','restart',
'rotate_right','rotate_left','rotate_right2','rotate_left2','',
'rotate_right','rotate_left','rotate_right2','rotate_left2'
} 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
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
---Trigger release action, don't need ``self._hovering`` to ``true``
function button:release(x, y, touchID)
local valid = true
local valid
if touchID then
valid = touchID == self._touchID
else
valid = true
end
if valid then
self._pressed = false
self._touchID = false
@@ -187,7 +187,7 @@ function BUTTON.checkDataValidation(D, safe)
elseif type(D.text) ~= 'string' then
error("[text] must be a string or a function returns string, got "..type(D.text))
end
assert(type(D.x) == "number" , "[x] 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")

View File

@@ -60,22 +60,25 @@ BUTTON.setDefaultOption{
}
-- Graphics
ShowLoadingText('backgrounds')
local gc_newImage, gc_newVideo = love.graphics.newImage, love.graphics.newVideo
BACKGROUNDS = {
[0] = gc_newVideo("res/backgrounds/green_waterfall.ogv", {audio=false}),
gc_newVideo("res/backgrounds/water.ogv", {audio=false}),
gc_newVideo("res/backgrounds/green_streams.ogv", {audio=false}),
gc_newVideo("res/backgrounds/streams.ogv", {audio=false}),
gc_newVideo("res/backgrounds/red_forest_waterfall.ogv", {audio=false}),
gc_newVideo("res/backgrounds/flowers_rain.ogv", {audio=false}),
gc_newVideo("res/backgrounds/moonlight_tree.ogv", {audio=false}),
gc_newVideo("res/backgrounds/lisa_frank.ogv", {audio=false}),
gc_newVideo("res/backgrounds/snowy_trees.ogv", {audio=false}),
gc_newVideo("res/backgrounds/snowy_cabin.ogv", {audio=false}),
}
BACKGROUNDS = {}
LILY.loadMulti{
{'newVideo', "res/backgrounds/green_waterfall.ogv", {audio=false}},
{'newVideo', "res/backgrounds/water.ogv", {audio=false}},
{'newVideo', "res/backgrounds/green_streams.ogv", {audio=false}},
{'newVideo', "res/backgrounds/streams.ogv", {audio=false}},
{'newVideo', "res/backgrounds/red_forest_waterfall.ogv", {audio=false}},
{'newVideo', "res/backgrounds/flowers_rain.ogv", {audio=false}},
{'newVideo', "res/backgrounds/moonlight_tree.ogv", {audio=false}},
{'newVideo', "res/backgrounds/lisa_frank.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 = {
["2tie"] = {
R = gc_newImage("res/img/r.png"),
@@ -112,21 +115,30 @@ COLOUR_SCHEMES = {
}
-- BGMs and SFXs
ShowLoadingText('BGMs & SFXs')
local audio_newSource = love.audio.newSource
SOUNDS = {
bottom = audio_newSource("res/se/bottom.wav", "static"),
lock = audio_newSource("res/se/lock.wav", "static"),
erase = audio_newSource("res/se/erase.wav", "static"),
fall = audio_newSource("res/se/fall.wav", "static"),
ready = audio_newSource("res/se/ready.wav", "static"),
promote = audio_newSource("res/se/promote.wav", "static"),
demote = audio_newSource("res/se/demote.wav", "static"),
autopromote = audio_newSource("res/se/autopromote.wav", "static"),
bgm_firsthalf = audio_newSource("res/bgm/firsthalf.flac", "static"),
bgm_secondhalf = audio_newSource("res/bgm/secondhalf.flac", "static"),
bgm_title = audio_newSource("res/bgm/title.flac", "static")
}
SOUNDS = {}
LILY.loadMulti{
{"newSource", "res/se/bottom.wav", "static"},
{"newSource", "res/se/lock.wav", "static"},
{"newSource", "res/se/erase.wav", "static"},
{"newSource", "res/se/fall.wav", "static"},
{"newSource", "res/se/ready.wav", "static"},
{"newSource", "res/se/promote.wav", "static"},
{"newSource", "res/se/demote.wav", "static"},
{"newSource", "res/se/autopromote.wav", "static"},
{"newSource", "res/bgm/firsthalf.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)
if sound ~= nil then

View File

@@ -12,26 +12,13 @@ if not love.filesystem.getInfo(REPLAY_DIR) then
love.filesystem.createDirectory(REPLAY_DIR)
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()
MOBILE = CURRENT_OS == "Android" or CURRENT_OS == "iOS"
LOADING_IMAGE_FILE = love.graphics.newImage('res/loading.png')
--- Show the loading text while we are loading resources<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
LILY = require "libs.lily"
function love.load()
require 'funcs'
@@ -53,17 +40,6 @@ function love.load()
require "game.vctrl" -- VCTRL
SCENE = LoadingScene()
-- VCTRL.new{ -- up down left right --- right left down up
-- -- {type='button',x= 100,y=320,key= 'up',r=35,iconSize=60,alpha=0.75},
-- -- {type='button',x= 100,y=440,key= 'down',r=35,iconSize=60,alpha=0.75},
-- -- {type='button',x= 40,y=380,key= 'left',r=35,iconSize=60,alpha=0.75},
-- -- {type='button',x= 160,y=380,key= 'right',r=35,iconSize=60,alpha=0.75},
-- -- {type='button',x=640- 40,y=380,key= 'rotate_left',r=35,iconSize=60,alpha=0.75},
-- -- {type='button',x=640-160,y=380,key= 'rotate_left2',r=35,iconSize=60,alpha=0.75},
-- -- {type='button',x=640-100,y=440,key= 'rotate_right',r=35,iconSize=60,alpha=0.75},
-- -- {type='button',x=640-100,y=320,key='rotate_right2',r=35,iconSize=60,alpha=0.75},
-- }
VCTRL.new(SETTINGS.input.virtual)
end
@@ -148,7 +124,7 @@ function love.keypressed(key, scancode)
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 == "f3" then SCENE = UserManagementScene()
elseif scancode == "f12" then LLDEBUGGER.requestBreak()
-- elseif scancode == "f11" then SETTINGS.firstTime = true
-- function keys are reserved
@@ -305,6 +281,10 @@ end
function love.focus(f) end
function love.quit()
LILY.quit()
end
local TARGET_FPS = 60
function love.run()

View File

@@ -1,5 +1,6 @@
local KeyConfigScene = SCENE:extend()
KeyConfigScene.title = "Key Config"
local buttonList = {}
local configurable_inputs = {
"menu_decide",
@@ -13,7 +14,6 @@ local configurable_inputs = {
"rotate_right",
"rotate_right2",
}
local input_names = {
menu_decide='Confirm Selection',
menu_back = 'Go Back',
@@ -40,13 +40,49 @@ function KeyConfigScene:new()
self.input_state = 1
self.set_inputs = newSetInputs()
self.new_input = {}
BUTTON.reset(buttonList)
buttonList = { -- Configuring
BUTTON.new{
text = CHAR.icon.fastForward.." SKIP",
x = 40, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "tab"} end
},
BUTTON.new{
text = CHAR.icon.cross_thick.." Cancel",
x = 150, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end
},
}
end
function KeyConfigScene:update()
if self.input_state > #configurable_inputs then
BUTTON.reset(buttonList)
buttonList = { -- Confirming
BUTTON.new{
text = CHAR.icon.checkMark.." CONFIRM",
x = 40, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "return"} end
},
BUTTON.new{
text = CHAR.icon.retry_spin.." Restart",
x = 150, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "delete"} end
},
BUTTON.new{
text = CHAR.icon.cross_thick.." Cancel",
x = 260, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end
}
}
end
end
function KeyConfigScene:render()
MainBackground()
BUTTON.draw(buttonList)
for i, input in ipairs(configurable_inputs) do
drawText(input_names[input], 40, 60 + i * 20, 200, "left")
if self.set_inputs[input] then
@@ -62,7 +98,9 @@ function KeyConfigScene:render()
end
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
if e.scancode == "escape" or (self.input_state > #configurable_inputs and e.input == "menu_back") then
SCENE = InputConfigScene(SETTINGS.firstTime)
@@ -72,10 +110,7 @@ function KeyConfigScene:onInputPress(e)
SCENE = SETTINGS.firstTime and TitleScene() or InputConfigScene()
SETTINGS.firstTime = false
elseif e.scancode == "delete" or e.scancode == "backspace" then
-- retry
self.input_state = 1
self.set_inputs = newSetInputs()
self.new_input = {}
self:new() -- retry
end
elseif e.scancode == "tab" then
self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
@@ -92,4 +127,16 @@ function KeyConfigScene:onInputPress(e)
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

View File

@@ -1,10 +1,21 @@
local LoadingScene = SCENE:extend()
local LoadingImageFile = love.graphics.newImage('res/loading.png')
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
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
return LoadingScene

View File

@@ -42,7 +42,7 @@ function NameEntryScene:new()
self.char_pos = 1
self.name_entry = {'A','A','A'}
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.repeat_limit = 10
self.repeat_counter = self.repeat_limit-1
@@ -130,7 +130,7 @@ function NameEntryScene:update()
end
self.repeat_counter = self.repeat_counter + 1
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
function NameEntryScene:onInputMove(e)
@@ -146,16 +146,15 @@ function NameEntryScene:getPlayInfo(player_name)
self.wins = grade_history[2]
self.plays = grade_history[4]
else
self.grade, self.win, self.plays = 0, 0, 0
self.grade, self.wins, 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])
local name = string.lower(table.concat(self.name_entry, '', 1, 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)
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
@@ -170,14 +169,12 @@ function NameEntryScene:onInputPress(e)
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 self:getPlayInfo(name)
elseif 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
self.entry_pos = self.entry_pos + 1
elseif e.input == "left" or e.scancode == "left" then
self.direction = "left"
elseif e.input == "right" or e.scancode == "right" then
@@ -199,6 +196,10 @@ end
function NameEntryScene:onInputRelease(e)
if e.type == "mouse" or e.type == "touch" then
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
self.direction = nil
self.repeat_counter = self.repeat_limit-1

View File

@@ -1,48 +1,68 @@
local ReplaySelectScene = SCENE:extend()
ReplaySelectScene.title = "Replay"
local scene_self
local replay_list
local buttonList = {
BUTTON.new{
text = CHAR.key.up.."\nUP", font = FONT_big,
x = 425, y = 80, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "up"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "up"} end
x = 325, y = 385, w = 100, h = 30,
text = CHAR.key.up.." Page up",
codeWhenReleased = function()
if scene_self.page == 1 then
scene_self.page = 1 + math.floor(#scene_self.replays / scene_self.page_flip)
else
scene_self.page = scene_self.page - 1
end
scene_self.replay_select = 1;
end
},
BUTTON.new{
text = CHAR.key.down.."\nDOWN", font = FONT_big,
x = 425, y = 240, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "down"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "down"} end
x = 435, y = 385, w = 100, h = 30,
text = CHAR.key.down.." Page down",
codeWhenReleased = function()
if scene_self.page < 1 + math.floor(#scene_self.replays / scene_self.page_flip) then
scene_self.page = scene_self.page + 1
else
scene_self.page = 1
end
scene_self.replay_select = 1;
end
},
BUTTON.new{
text = CHAR.icon.play.."\nPLAY", font = FONT_big,
x = 345, y = 160, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "menu_decide"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "menu_decide"} end
x = 105, y = 385, w = 100, h = 30,
text = CHAR.icon.play.." Play",
codeWhenPressed = function() scene_self:onInputPress {input = "menu_decide"} end,
codeWhenReleased = function() scene_self:onInputRelease{input = "menu_decide"} end
},
BUTTON.new{
text = CHAR.icon.home.."\nHOME", font = FONT_big,
x = 505, y = 160, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "menu_back"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "menu_back"} end
x = 105, y = 425, w = 100, h = 30,
text = CHAR.icon.home.." Home",
codeWhenPressed = function() scene_self:onInputPress {input = "menu_back"} end,
codeWhenReleased = function() scene_self:onInputRelease{input = "menu_back"} end
},
BUTTON.new{
text = CHAR.icon.export.."\nEXP.", font = FONT_big,
x = 345, y = 320, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "rotate_left"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "rotate_left"} end
x = 215, y = 425, w = 100, h = 30,
text = CHAR.icon.save.." Converter",
codeWhenReleased = function() love.system.openURL("https://sweetsea-butimnotsweet.github.io/tromi_replay_converter/") end
},
BUTTON.new{
text = CHAR.icon.import.."\nIMP.", font = FONT_big,
x = 505, y = 320, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "rotate_right"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "rotate_right"} end
x = 325, y = 425, w = 100, h = 30,
text = CHAR.icon.export.." Export",
codeWhenPressed = function() scene_self:onInputPress {input = "rotate_left"} end,
codeWhenReleased = function() scene_self:onInputRelease{input = "rotate_left"} end
},
BUTTON.new{
x = 435, y = 425, w = 100, h = 30,
text = CHAR.icon.import.." Import",
codeWhenPressed = function() scene_self:onInputPress {input = "rotate_right"} end,
codeWhenReleased = function() scene_self:onInputRelease{input = "rotate_right"} end
},
}
function ReplaySelectScene:new()
self:initList()
scene_self = self
BUTTON.reset(buttonList)
PENTO_MODE = false
end
@@ -51,7 +71,7 @@ function ReplaySelectScene:initList()
replay_list = love.filesystem.getDirectoryItems('saves/replays/')
table.sort(replay_list, function(a,b) return a > b end)
self.replay_text = {}
self.page_flip = 16
self.page_flip = 10
self.page = 1
local gradeNames = {
"19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k",
@@ -81,13 +101,15 @@ end
function ReplaySelectScene: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, 20 + 20 * self.replay_select, 640, 22)
love.graphics.rectangle("fill", 0, 15 + 30 * self.replay_select, 640, 27)
BUTTON.draw(buttonList)
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, math.floor(#self.replays / self.page_flip) + 1), 215, 390, 100, "center")
local i, j = 1, 1
while i <= #self.replay_text do
@@ -95,7 +117,7 @@ function ReplaySelectScene:render()
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 + 20 * j, 1000, "left")
drawText(self.replay_text[i], 40, 20 + 30 * j, 1000, "left")
end
j = j + 1
i = i + 1
@@ -145,8 +167,15 @@ function ReplaySelectScene:onInputPress(e)
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)]
if e.type == "touch" or e.type == "mouse" then
BUTTON.press(buttonList, e.x, e.y, e.id)
if (e.type == "touch" or e.type == "mouse") and not BUTTON.press(buttonList, e.x, e.y, e.id) 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
if self.replays[1] == nil then SCENE = TitleScene(); return
else

View File

@@ -1,5 +1,6 @@
local StickConfigScene = SCENE:extend()
StickConfigScene.title = "Controller Config"
local buttonList = {}
local configurable_inputs = {
"menu_decide",
@@ -13,7 +14,6 @@ local configurable_inputs = {
"rotate_right",
"rotate_right2",
}
local input_names = {
menu_decide='Confirm Selection',
menu_back = 'Go Back',
@@ -40,13 +40,49 @@ function StickConfigScene:new()
self.set_inputs = newSetInputs()
self.new_input = {}
self.axis_timer = 0
BUTTON.reset(buttonList)
buttonList = { -- Configuring
BUTTON.new{
text = CHAR.icon.fastForward.." SKIP",
x = 40, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "tab"} end
},
BUTTON.new{
text = CHAR.icon.cross_thick.." Cancel",
x = 150, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end
},
}
end
function StickConfigScene:update()
if self.input_state > #configurable_inputs then
BUTTON.reset(buttonList)
buttonList = { -- Confirming
BUTTON.new{
text = CHAR.icon.checkMark.." CONFIRM",
x = 40, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "return"} end
},
BUTTON.new{
text = CHAR.icon.retry_spin.." Restart",
x = 150, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "delete"} end
},
BUTTON.new{
text = CHAR.icon.cross_thick.." Cancel",
x = 260, y = 300, w = 100, h = 30,
codeWhenReleased = function() self:onInputPress{type = "key", scancode = "escape"} end
}
}
end
end
function StickConfigScene:render()
MainBackground()
BUTTON.draw(buttonList)
for i, input in ipairs(configurable_inputs) do
drawText(input_names[input], 40, 60 + i * 20, 200, "left")
if self.set_inputs[input] then
@@ -68,23 +104,21 @@ local function addJoystick(input, name)
end
end
---@param e SCENE_onInput
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
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
if e.scancode == "return" or e.input == "" 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
SCENE = had_config and InputConfigScene() or TitleScene()
if e.scancode == "return" or e.input == "menu_decide" then
SETTINGS.input.keys = self.new_input
SCENE = SETTINGS.firstTime and TitleScene() or InputConfigScene()
SETTINGS.firstTime = false
elseif e.scancode == "delete" or e.scancode == "backspace" then
-- retry
self.input_state = 1
self.set_inputs = newSetInputs()
self.new_input = {}
self:new() -- retry
end
else -- Other keys - skip
self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
@@ -149,4 +183,16 @@ function StickConfigScene:onInputPress(e)
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

View File

@@ -69,7 +69,7 @@ function Title2Scene:render()
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("Mobile 1.1 - PC 2.3", 150, 78, 200, "left")
drawText("https://mycophobia.org\nhttps://github.com/SweetSea-ButImNotSweet/", 40, 100, 300, "left")
if PENTO_MODE then

View File

@@ -54,7 +54,7 @@ end
function TrainingScene:onInputPress(e)
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)
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()
elseif (e.input == "menu_back") then
SCENE = TitleScene()

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