3 Commits

Author SHA1 Message Date
Squishy (C6H12O6+NaCl+H2O)
c14c702d17 Update touch control 2024-05-29 00:26:05 +07:00
Squishy (C6H12O6+NaCl+H2O)
9679378b1b Add importing and exporting replays 2024-05-29 00:09:48 +07:00
Squishy (C6H12O6+NaCl+H2O)
d7726c1854 Add icon font 2024-05-28 23:43:16 +07:00
12 changed files with 538 additions and 19 deletions

View File

@@ -71,7 +71,7 @@ A small note about the music:
# Special thanks
* mycophobia for writing the original Tromi
* MrZ_26 for the base of ``VCTRL`` module (yea I stole from him his code ;-;)
* C₂₉H₂₅N₃O₅ for his virtual key design, I used it during developing when I hadn't made my own yet
* C₂₉H₂₅N₃O₅ for his virtual key design (used while during inital development), and icon font (actually I extracted and re-pack as a new font from his orginal production file)
# Don't forget to check
* [Original Tromi](https://mycophobia.org/tromi)

415
char.lua Normal file
View File

@@ -0,0 +1,415 @@
local function utf8_convert(n)
local floorint = math.floor
local char = string.char
assert(type(n)=='number',"Wrong type ("..type(n)..")")
assert(n>=0 and n<2^31,"Out of range ("..n..")")
if n<2^7 then return char(n)
elseif n<2^11 then return char(192+floorint(n/2^06),128+n%2^6)
elseif n<2^16 then return char(224+floorint(n/2^12),128+floorint(n/2^06)%2^6,128+n%2^6)
elseif n<2^21 then return char(240+floorint(n/2^18),128+floorint(n/2^12)%2^6,128+floorint(n/2^06)%2^6,128+n%2^6)
elseif n<2^26 then return char(248+floorint(n/2^24),128+floorint(n/2^18)%2^6,128+floorint(n/2^12)%2^6,128+floorint(n/2^06)%2^6,128+n%2^6)
elseif n<2^31 then return char(252+floorint(n/2^30),128+floorint(n/2^24)%2^6,128+floorint(n/2^18)%2^6,128+floorint(n/2^12)%2^6,128+floorint(n/2^06)%2^6,128+n%2^6)
end
end
local L={
zChan={-- F0000 - F003F
none= 0xF0000,
normal= 0xF0001,
full= 0xF0002,
happy= 0xF0003,
confused= 0xF0004,
grinning= 0xF0005,
frowning= 0xF0006,
tears= 0xF0007,
anxious= 0xF0008,
rage= 0xF0009,
fear= 0xF000A,
question= 0xF000B,
angry= 0xF000C,
shocked= 0xF000D,
ellipses= 0xF000E,
sweatDrop= 0xF000F,
cry= 0xF0010,
cracked= 0xF0011,
qualified= 0xF0012,
unqualified= 0xF0013,
understand= 0xF0014,
thinking= 0xF0015,
spark= 0xF0016,
},
mino={-- F0040 - F007F
Z=0xF0040,
S=0xF0041,
J=0xF0042,
L=0xF0043,
T=0xF0044,
O=0xF0045,
I=0xF0046,
Z5=0xF0047,
S5=0xF0048,
P= 0xF0049,
Q= 0xF004A,
F= 0xF004B,
E= 0xF004C,
T5=0xF004D,
U= 0xF004E,
V= 0xF004F,
W= 0xF0050,
X= 0xF0051,
J5=0xF0052,
L5=0xF0053,
R= 0xF0054,
Y= 0xF0055,
N= 0xF0056,
H= 0xF0057,
I5=0xF0058,
I3=0xF0059,
C= 0xF005A,
I2=0xF005B,
O1=0xF005C,
},
icon={-- F0080 - F00FF
menu= 0xF0080,
music= 0xF0081,
language= 0xF0082,
back= 0xF0083,
play_pause= 0xF0084,
info= 0xF0085,
help= 0xF0086,
mute= 0xF0087,
volume_up= 0xF0088,
volume_down= 0xF0089,
retry_spin= 0xF008A,
filledLogo= 0xF008B,
hollowLogo= 0xF008C,
toUp= 0xF008D,
toDown= 0xF008E,
toLeft= 0xF008F,
toRight= 0xF0090,
checkMark= 0xF0091,
crossMark= 0xF0092,
musicMark= 0xF0093,
infoMark= 0xF0094,
warnMark= 0xF0095,
console= 0xF0096,
globe= 0xF0097,
video_camera= 0xF0098,
settings= 0xF0099,
mrz= 0xF009A,
apple= 0xF009B,
home= 0xF009C,
cross_thick= 0xF009D,
num0InSpin= 0xF009E,
num1InSpin= 0xF009F,
num2InSpin= 0xF00A0,
num3InSpin= 0xF00A1,
num4InSpin= 0xF00A2,
play= 0xF00A3,
pause= 0xF00A4,
nextFrame= 0xF00A5,
yen= 0xF00A6,
dollar= 0xF00A7,
euro= 0xF00A8,
pound= 0xF00A9,
bitcoin= 0xF00AA,
onebag= 0xF00AB,
export= 0xF00AC,
import= 0xF00AD,
trash= 0xF00AE,
loadOne= 0xF00AF,
saveOne= 0xF00B0,
loadTwo= 0xF00B1,
saveTwo= 0xF00B2,
zBook= 0xF00B3,
rankX= 0xF00B4,
rankU= 0xF00B5,
rankA= 0xF00B6,
rankB= 0xF00B7,
rankC= 0xF00B8,
rankD= 0xF00B9,
rankE= 0xF00BA,
rankF= 0xF00BB,
rankZ= 0xF00BC,
rankS= 0xF00C2,
speedOneEights= 0xF00BD,
speedOneHalf= 0xF00BE,
speedOne= 0xF00BF,
speedTwo= 0xF00C0,
speedFive= 0xF00C1,
bone= 0xF00C3,
invis= 0xF00C4,
bomb= 0xF00C5,
garbage= 0xF00C6,
copy= 0xF00C7,
tas= 0xF00C8,
pencil= 0xF00C9,
magGlass= 0xF00CA,
zoomIn= 0xF00CB,
zoomOut= 0xF00CC,
zoomDefault= 0xF00CD,
share= 0xF00CE,
save= 0xF00CF,
fastForward= 0xF00D0,
rewind= 0xF00D1,
nextSong= 0xF00D2,
previousSong= 0xF00D3,
cycle= 0xF00D4,
cycleOne= 0xF00D5,
cycleOff= 0xF00D6,
random= 0xF00D7,
randomOff= 0xF00D8,
randomAuto= 0xF00D9,
closedCaption= 0xF00DA,
fullBeat= 0xF00DB,
rewind10= 0xF00DC,
rewind30= 0xF00DD,
foward10= 0xF00DE,
foward30= 0xF00DF,
fontUp= 0xF00E0,
fontDown= 0xF00E1,
erase= 0xF00E2,
auto= 0xF00E3,
},
key={-- F0100 - F017F
macCmd= 0xF0100,
macOpt= 0xF0101,
macCtrl= 0xF0102,
shift= 0xF0103,
capsLock= 0xF0104,
enter_or_return= 0xF0105,
backspace= 0xF0106,
clear= 0xF0107,
macFowardDel= 0xF0108,
macEsc= 0xF0109,
macTab= 0xF010A,
fn= 0xF010B,
macHome= 0xF010C,
macEnd= 0xF010D,
macPgup= 0xF010E,
macPgdn= 0xF010F,
macEnter= 0xF0110,
space= 0xF0111,
windows= 0xF0112,
alt= 0xF0113,
ctrl= 0xF0114,
winMenu= 0xF0115,
tab= 0xF0116,
esc= 0xF0117,
up= 0xF0118,
down= 0xF0119,
left= 0xF011A,
right= 0xF011B,
del= 0xF011C,
enterText= 0xF011D,
keyboard= 0xF011E,
macMediaEject= 0xF011F,
isoCtrl= 0xF0120,
isoAlt= 0xF0121,
macHomeAlt= 0xF0122,
macEndAlt= 0xF0123,
macPgupAlt= 0xF0124,
macPgdnAlt= 0xF0125,
iecPower= 0xF0126,
},
controller={-- F0180 - F01FF
xbox= 0xF0180,
lt= 0xF0181,
rt= 0xF0182,
lb= 0xF0183,
rb= 0xF0184,
xboxX= 0xF0185,
xboxY= 0xF0186,
xboxA= 0xF0187,
xboxB= 0xF0188,
joystickL= 0xF0189,
joystickR= 0xF018A,
jsLU= 0xF018B,
jsLD= 0xF018C,
jsLR= 0xF018D,
jsLL= 0xF018E,
jsRU= 0xF018F,
jsRD= 0xF0190,
jsRR= 0xF0191,
jsRL= 0xF0192,
jsLPress= 0xF0193,
jsRPress= 0xF0194,
dpad= 0xF0195,
dpadU= 0xF0196,
dpadD= 0xF0197,
dpadL= 0xF0198,
dpadR= 0xF0199,
xboxView= 0xF019A,
xboxMenu= 0xF019B,
xboxShare= 0xF019C,
xboxConnect= 0xF019D,
ps= 0xF019E,
psTriangle= 0xF019F,
psCircle= 0xF01A0,
psCross= 0xF01A1,
psSquare= 0xF01A2,
psMute= 0xF01A3,
psCreate= 0xF01A4,
psOption= 0xF01A5,
},
mahjong={-- F0200 - F027F
m1= 0xF0200,
m2= 0xF0201,
m3= 0xF0202,
m4= 0xF0203,
m5= 0xF0204,
m6= 0xF0205,
m7= 0xF0206,
m8= 0xF0207,
m9= 0xF0208,
s1= 0xF0209,
s2= 0xF020A,
s3= 0xF020B,
s4= 0xF020C,
s5= 0xF020D,
s6= 0xF020E,
s7= 0xF020F,
s8= 0xF0210,
s9= 0xF0211,
p1= 0xF0212,
p2= 0xF0213,
p3= 0xF0214,
p4= 0xF0215,
p5= 0xF0216,
p6= 0xF0217,
p7= 0xF0218,
p8= 0xF0219,
p9= 0xF021A,
ton= 0xF021B,
nan= 0xF021C,
sha= 0xF021D,
pe= 0xF021E,
chun= 0xF021F,
hatsu= 0xF0220,
haku= 0xF0221,
hatsuAlt= 0xF0222,
hakuAlt= 0xF0223,
haru= 0xF0224,
natsu= 0xF0225,
aki= 0xF0226,
fuyu= 0xF0227,
ume= 0xF0228,
ran= 0xF0229,
kiku= 0xF022A,
take= 0xF022B,
m5Red= 0xF022C,
s5Red= 0xF022D,
p5Red= 0xF022E,
m1Base= 0xF022F,
m2Base= 0xF0230,
m3Base= 0xF0231,
m4Base= 0xF0232,
m5Base= 0xF0233,
m6Base= 0xF0234,
m7Base= 0xF0235,
m8Base= 0xF0236,
m9Base= 0xF0237,
mComb= 0xF0238,
s1Base= 0xF0239,
s1Comb= 0xF023A,
s5Base= 0xF023B,
s5Comb= 0xF023C,
s7Base= 0xF023D,
s7Comb= 0xF023E,
s9Base= 0xF023F,
s9Comb= 0xF0240,
p2Base= 0xF0241,
p2Comb= 0xF0242,
p3Base= 0xF0243,
p3Comb1= 0xF0244,
p3Comb2= 0xF0245,
p4Base= 0xF0246,
p4Comb= 0xF0247,
p5Base= 0xF0248,
p5Comb1= 0xF0249,
p5Comb2= 0xF024A,
p6Base= 0xF024B,
p6Comb= 0xF024C,
p7Base= 0xF024D,
p7Comb= 0xF024E,
p9Base= 0xF024F,
p9Comb1= 0xF0250,
p9Comb2= 0xF0251,
frameComb= 0xF0252,
s1j= 0xF0253,
s1jBase= 0xF0254,
s1jComb= 0xF0255,
},
cards={-- F0300 - F070F
cardBack= 0xF0300,
clubA= 0xF0301,
club2= 0xF0302,
club3= 0xF0303,
club4= 0xF0304,
club5= 0xF0305,
club6= 0xF0306,
club7= 0xF0307,
club8= 0xF0308,
club9= 0xF0309,
club10= 0xF030A,
clubJ= 0xF030B,
clubC= 0xF030C,
clubQ= 0xF030D,
clubK= 0xF030E,
heartA= 0xF0401,
heart2= 0xF0402,
heart3= 0xF0403,
heart4= 0xF0404,
heart5= 0xF0405,
heart6= 0xF0406,
heart7= 0xF0407,
heart8= 0xF0408,
heart9= 0xF0409,
heart10= 0xF040A,
heartJ= 0xF040B,
heartC= 0xF040C,
heartQ= 0xF040D,
heartK= 0xF040E,
diamondA= 0xF0501,
diamond2= 0xF0502,
diamond3= 0xF0503,
diamond4= 0xF0504,
diamond5= 0xF0505,
diamond6= 0xF0506,
diamond7= 0xF0507,
diamond8= 0xF0508,
diamond9= 0xF0509,
diamond10= 0xF050A,
diamondJ= 0xF050B,
diamondC= 0xF050C,
diamondQ= 0xF050D,
diamondK= 0xF050E,
jokerBlack= 0xF050F,
clubA= 0xF0601,
club2= 0xF0602,
club3= 0xF0603,
club4= 0xF0604,
club5= 0xF0605,
club6= 0xF0606,
club7= 0xF0607,
club8= 0xF0608,
club9= 0xF0609,
club10= 0xF060A,
clubJ= 0xF060B,
clubC= 0xF060C,
clubQ= 0xF060D,
clubK= 0xF060E,
jokerWhite= 0xF060F,
}
}
for _,pack in next,L do
for name,unicode in next,pack do
pack[name]=utf8_convert(unicode)
end
end
return L

View File

@@ -15,7 +15,7 @@ function GameMode:new(player_name, input_file, replay_grade)
if player_name == nil then self.training = true else self.training = false end
if input_file ~= nil then
input_file = love.filesystem.newFile(REPLAY_DIR..input_file, 'r'):read()
input_file = love.filesystem.read(REPLAY_DIR..input_file)
input_file = lualzw.decompress(input_file)
local seed = self:getInputPieceSeq(input_file)
self.replay_inputs = self:getReplayInputs(input_file)
@@ -677,6 +677,7 @@ function GameMode:onPieceEnter()
end
function GameMode:onGameOver()
if not self.training then VCTRL.toggle(false) end
if not self.input_playback and not self.training and not PENTO_MODE then
if not self.did_grades then
self.grade_score = self.grade_score + self.speed_level

View File

@@ -2,6 +2,10 @@
FONT_tromi = love.graphics.newFont('res/fonts/monofonto rg.otf', 28)
FONT_big = love.graphics.newFont('res/fonts/monofonto rg.otf', 56)
FONT_tromi:setFallbacks(love.graphics.newFont('res/fonts/icon.otf', 28))
FONT_big :setFallbacks(love.graphics.newFont('res/fonts/icon.otf', 56))
CHAR = require("char")
local font_height = FONT_tromi:getHeight() * 0.5
local font_big_height = FONT_big:getHeight() * 0.5

View File

@@ -52,9 +52,11 @@ function love.load()
require "game.vctrl" -- VCTRL
function SCENE.update()
SCENE.update = function() end
SCENE = SETTINGS.firstTime and InputConfigScene(true) or TitleScene()
end
function SCENE.render()
SCENE.render = function() end
love.graphics.draw(LOADING_IMAGE_FILE,0,0,0,0.5)
end

View File

@@ -35,6 +35,7 @@ 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"
@@ -44,7 +45,7 @@ TouchConfigPreviewScene = require "scene.touch_config_preview"
InputConfigScene = require "scene.input_config"
ReplaySelectScene = require "scene.replay"
TrainingScene = require "scene.training"
ReplayTestScene = require"scene.replay_test"
FullscreenScene = require "scene.fullscreen"
MusicToggleScene = require "scene.music_toggle"

BIN
res/fonts/icon.otf Normal file

Binary file not shown.

View File

@@ -70,7 +70,7 @@ function ConfigScene:new(first_time)
updateButtonList(self)
secret_code_used = false
secret_code_input = {} -- When it matches 79338732 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
if first_time then
@@ -88,10 +88,10 @@ function ConfigScene:render()
if SETTINGS.tvMode then
drawText("TV mode is ON now! Check keybind below", 80, 40, 1000)
drawText("Which controls do you want to configure?", 80, 70, 1000)
drawText(
"2 - Up 1 - Rotate left 5 - Confirm selection\n"..
"8 - Right 3 - Rotate right 0 - Back\n"..
"4 - Left 7 - Rotate left 2\n"..
drawText(
"2 - Up 1 - Rotate left 5 - Confirm selection\n"..
"8 - Right 3 - Rotate right 0 - Back\n"..
"4 - Left 7 - Rotate left 2\n"..
"6 - Down 9 - Rotate right 2", 80, 350, 1000
)
else
@@ -128,7 +128,7 @@ function ConfigScene:onInputMove(e)
end
---@param key string
local function checkSecretCodeInput(self, key)
local function checkSecretCodeInput(key)
if secret_code_used then return end
if key:sub(1, 2) == "kp" then
table.insert(secret_code_input, key:sub(3,3))
@@ -160,7 +160,7 @@ local function checkSecretCodeInput(self, key)
SETTINGS.firstTime = false
SETTINGS.tvMode = true
secret_code_used = true
updateButtonList(self)
updateButtonList(SCENE)
elseif current_code == "........" then
SETTINGS.input.keys = {}
SETTINGS.tvMode = false
@@ -183,7 +183,7 @@ function ConfigScene:onInputPress(e)
) then
SCENE = TitleScene()
end
checkSecretCodeInput(self, e.key or "")
checkSecretCodeInput(e.key or "")
end
function ConfigScene:onInputRelease(e)
if e.type == "touch" or e.type == "mouse" then

View File

@@ -27,6 +27,18 @@ local buttonList = {
codeWhenPressed = function() SCENE:onInputPress {input = "menu_back"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "menu_back"} end
},
BUTTON.new{
text = CHAR.icon.export.."\nCOPY", 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
},
BUTTON.new{
text = CHAR.icon.import.."\nPASTE", 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
},
}
function ReplaySelectScene:new()
@@ -135,7 +147,7 @@ function ReplaySelectScene:onInputPress(e)
if e.type == "touch" or e.type == "mouse" then
BUTTON.press(buttonList, e.x, e.y, e.id)
elseif e.input == "menu_decide" or e.input == "rotate_left" or e.scancode == "return" then
elseif e.input == "menu_decide" or e.scancode == "return" then
if self.replays[1] == nil then SCENE = TitleScene(); return
else
local line_components = {}
@@ -146,15 +158,30 @@ function ReplaySelectScene:onInputPress(e)
local player_grade = string.gsub(line_components[2], " ", "")
SCENE = GameScene(player_name, selected_replay, player_grade)
end
-- elseif e.input == "rotate_right" then -- Will add in future, not now
-- love.system.setClipboardText(love.data.encode("string", "base64", love.filesystem.read('saves/replays/'..selected_replay)))
elseif e.input == "rotate_left" then -- Export
local plain_replay_data = love.data.encode("string", "base64", love.filesystem.read(REPLAY_DIR..selected_replay))
love.system.setClipboardText(("BEGINNING_OF_TROMI_REPLAY|%s|%s|END_OF_TROMI_REPLAY"):format(selected_replay, plain_replay_data))
elseif e.input == "rotate_right" then -- Import
local input_data = love.system.getClipboardText()
if input_data:find("BEGINNING_OF_TROMI_REPLAY|", 1, true) == 1 and input_data:find("|END_OF_TROMI_REPLAY", 1, true) == #input_data - 19 then
local data_part = input_data:sub(27, #input_data - 20)
local separator_pos = data_part:find("|", 1, true)
local replay_name = data_part:sub(1, separator_pos - 1)
local replay_path = REPLAY_DIR..replay_name
local replay_data = love.data.decode("string", "base64", data_part:sub(separator_pos + 1))
love.filesystem.write(replay_path, replay_data)
SCENE = ReplayTestScene(replay_name)
else
SCENE = ReplayTestScene()
end
elseif e.input == "up" or e.scancode == "up" then
if self.replays[1] == nil then SCENE = TitleScene(); return end
self.direction = 'up'
elseif e.input == "down" or e.scancode == "down" then
if self.replays[1] == nil then SCENE = TitleScene(); return end
self.direction = 'down'
elseif e.input == "menu_back" or e.input == "rotate_right" 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()
end
end

51
scene/replay_test.lua Normal file
View File

@@ -0,0 +1,51 @@
local ReplayTestScene = SCENE:extend()
local GAME
local error_message
local valid_data
function ReplayTestScene:new(input_file)
if not input_file then
valid_data = false
return
else
valid_data = true
end
self.input_file = input_file
GAME = require("game.gamemode")
local okay, err = pcall(function()
GAME:new("TRO", input_file, "19k")
GAME:initialize(require"game.rotation")
end)
if not okay then
-- TODO
error_message = err
love.filesystem.remove(REPLAY_DIR..self.input_file)
end
end
function ReplayTestScene:render()
MainBackground()
if valid_data then
if error_message then
drawText("Replay test failed! Data corrupted!", 80, 40, 1000)
drawText("Press any key to go back. Anyway here is the error info:", 80, 70, 1000)
drawText(error_message, 80, 100, 560)
else
drawText("Replay test finished!", 80, 40, 1000)
drawText("Your replay was imported. Press any key to go back.", 80, 70, 1000)
end
else
drawText("Replay test failed! Not Tromi's replay data", 80, 40, 1000)
drawText("Press any key to go back, and check your device's clipboard again!", 80, 100, 1000)
end
end
function ReplayTestScene:onInputRelease()
SCENE = ReplayTestScene()
end
return ReplayTestScene

View File

@@ -52,6 +52,24 @@ buttonList = {
SCENE = TouchConfigPreviewScene()
end
},
resetAll = BUTTON.new{
text = "RESET\nALL",
x = 570, y = 80, w = 60, h = 40,
codeWhenReleased = function()
local selection = love.window.showMessageBox(
"Save config?", "Are you really sure about RESETTING ALL touchscreen configuration?",
{"Yes", "No", escapebutton = 2, enterbutton = 1},
"info", true
)
if selection == 1 then
VCTRL.focus = nil; focusingButton = nil
hasChanged = false
VCTRL.clearAll()
VCTRL.new(SETTINGS.__default__.input.virtual)
SETTINGS.input.virtual = SETTINGS.__default__.input.virtual
end
end
},
menuScreen = BUTTON.new{
text = "MENU",
x = 570, y = 5, w = 60, h = 25,
@@ -59,7 +77,7 @@ buttonList = {
if hasChanged or SETTINGS.firstTime then
local selection = love.window.showMessageBox(
"Save config?", "Do you want to save your changes before exiting?",
{"Save", "Discard", "Keep editing", escapebutton = 2, enterbutton = 1},
{"Save", "Discard", "Keep editing", escapebutton = 3, enterbutton = 1},
"info", true
)
if selection == 1 then
@@ -145,12 +163,12 @@ local function sliderList_update()
end
end
function TouchConfigScene:new(fromPreviewScene)
function TouchConfigScene:new()
VCTRL.toggle(true)
VCTRL.focus = nil
focusingButton = nil
hasChanged = fromPreviewScene
Grid:new(10, 20)
-- TODO
end

View File

@@ -32,7 +32,7 @@ local _defaultSettings = {
}
SETTINGS = setmetatable(
{},
{__default__ = _defaultSettings},
{
__index = function(_, k)
if _settings[k] == nil then