13 Commits

Author SHA1 Message Date
Squishy (C6H12O6+NaCl+H2O)
c9a97856fd Update virtual control scene 2024-05-29 22:24:48 +07:00
Squishy (C6H12O6+NaCl+H2O)
8f902caa22 Update virtual control texture 2024-05-29 20:32:29 +07:00
Squishy (C6H12O6+NaCl+H2O)
4e0815e13a Updating README file 2024-05-29 15:53:29 +07:00
Squishy (C6H12O6+NaCl+H2O)
c555e98081 Replace font 2024-05-29 15:33:46 +07:00
Squishy (C6H12O6+NaCl+H2O)
fbfd9ee0db Update font related stuff 2024-05-29 10:34:57 +07:00
Squishy (C6H12O6+NaCl+H2O)
3c473fd5f3 convert indents to spaces 2024-05-29 10:01:34 +07:00
Squishy (C6H12O6+NaCl+H2O)
dd55171204 Replacing font, to avoid license issue 2024-05-29 09:56:59 +07:00
Squishy (C6H12O6+NaCl+H2O)
6beacc51f5 Update conf.lua 2024-05-29 00:27:15 +07:00
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
Squishy (C6H12O6+NaCl+H2O)
e79bf246bf Update README 2024-05-27 20:24:34 +07:00
SweetSea-ButImNotSweet
7cf450868a Fix virtual button method 2024-05-27 20:18:24 +07:00
24 changed files with 845 additions and 302 deletions

View File

@@ -36,22 +36,22 @@ Ported to Android (mobile and TV) by SweetSea with on-screen control (with some
Navigate to where you put ``tromi_mobile.love`` in the File manager (the one you downloaded from the link in Install for TV section), just opening and Tromi should be launched. Navigate to where you put ``tromi_mobile.love`` in the File manager (the one you downloaded from the link in Install for TV section), just opening and Tromi should be launched.
# Differences from original Tromi # Differences from original Tromi
> This is required, to follow the used license (GNU GPL v3) > I must make this list to follow the used license (GNU GPL v3)<br>
> :no_entry: There are ***very much*** breaking changes right now, and I can't always finish this list. I may try hard to do it.
* No differences in gameplay * No differences in gameplay
* Files will be saved into ``Android/data/org.love2d.android/tromi_mobile`` instead the location where the game files in * Files will be saved into ``Android/data/org.love2d.android/tromi_mobile`` instead the location where the game files in
* Add ``simple-button`` module, made by SweetSea * Add ``simple-button`` module, made by me (SweetSea)
* All UIs are touch-able * All UIs are touch-able
* Add on-screen buttons * Add on-screen buttons
* Replaced icons for 3 direction buttons (Left, Down, Right) * Replaced icons for 3 direction buttons (Left, Down, Right), using from Techmino's font (outdated image)
<img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/Replay_screen_differences.png"> <img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/Replay_screen_differences.png">
* Add a special pre-made keybind for Android TV (only supports TV models have their remote has numerical area (0-9))<img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/SPOILER_tv_code.png"> * Add a special pre-made keybind for Android TV (only supports TV models have their remote has numerical area (0-9))<img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/SPOILER_tv_code.png">
* <details><summary>Changes the way to input secret code to activate Pentominoes mode</summary><img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/SPOILER_pento_code.png">To insert the left arrow, tap on the left, so does to right arrow.</details> * <details><summary>Changes the way to input secret code to activate Pentominoes mode</summary><img src="https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile/raw/branch/main/screenshot/SPOILER_pento_code.png">To insert the left arrow, tap on the left, so does to right arrow.</details>
* Add a loading screen (this need to be updated later) * Add a loading screen ~~(this need to be updated later)~~
* Update ``binser`` library, this fixes some weird bugs related to saving * Update ``binser`` library, this fixes some weird bugs related to saving
* Replaced old Cambridge's ``config`` module with the new one inspired by "the sequel of Techmino"s ``SETTINGS`` module * Replaced old Cambridge's ``config`` module with the new one inspired by "the sequel of Techmino"s ``SETTINGS`` module
# TODO # TODO
- [ ] Add a way to export ~~replay~~ data for Android > 11 - [ ] 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)
@@ -63,15 +63,15 @@ Please read ``COPYING.txt`` for more information.<br>
A small note about the music: A small note about the music:
> Only mycophobia right now having the permission to music from Jerry Martin, I haven't got.<br> > Only mycophobia right now having the permission to music from Jerry Martin, I haven't got.<br>
> >
> I sent an email about this issue (not mentioning about this game), but I haven't got any replies from them (I checked both my main inbox and spam too, nothing)<br> > I sent an email about this issue (not mentioning about this game), but I haven't got any replies from them (I checked both my main inbox and spam too, nothing)<br>
> >
> Both me and mycophobia can't give you a sub-license if you ask. What can I do is suggesting you to send an email about this (there is a chance that you may not receive any replies, but it's better than do nothing) > Both me and mycophobia can't give you a sub-license if you ask. What can I do is suggesting you to send an email about this (there is a chance that you may not receive any replies, but it's better than do nothing)
# Special thanks # Special thanks
* mycophobia for writing the original Tromi * mycophobia for writing the original Tromi
* MrZ_26 for the base of ``VCTRL`` module (yea I stole from him his code ;-;) * 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 (from Techmino).
# Don't forget to check # Don't forget to check
* [Original Tromi](https://mycophobia.org/tromi) * [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

@@ -1,5 +1,5 @@
function love.conf(t) function love.conf(t)
t.identity = "tromi_ver3" t.identity = "tromi_mobile"
t.externalstorage=true t.externalstorage=true
t.console = true t.console = true

View File

@@ -143,6 +143,15 @@ function drawText(text, x, y, size, orientation, color)
love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5) love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5)
end end
function drawBoldText(text, x, y, size, orientation, color)
if color == nil then color = {1, 1, 1, 1} end
love.graphics.setFont(FONT_bold)
love.graphics.setColor(0, 0, 0, 0.8)
love.graphics.printf(text, x+1, y+1, size*2, orientation, nil, 0.50)
love.graphics.setColor(color)
love.graphics.printf(text, x, y, size*2, orientation, nil, 0.5)
end
function drawBigText(text, x, y, size, orientation, color) function drawBigText(text, x, y, size, orientation, color)
if color == nil then color = {1, 1, 1, 1} end if color == nil then color = {1, 1, 1, 1} end
love.graphics.setFont(FONT_big) love.graphics.setFont(FONT_big)

View File

@@ -13,9 +13,9 @@ 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)
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
if input_file ~= nil then 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) input_file = lualzw.decompress(input_file)
local seed = self:getInputPieceSeq(input_file) local seed = self:getInputPieceSeq(input_file)
self.replay_inputs = self:getReplayInputs(input_file) self.replay_inputs = self:getReplayInputs(input_file)
@@ -23,10 +23,10 @@ function GameMode:new(player_name, input_file, replay_grade)
self.input_playback = true self.input_playback = true
self.grade = replay_grade self.grade = replay_grade
self.frames = 1 self.frames = 1
elseif self.training then elseif self.training then
player_name = 'TRN' player_name = 'TRN'
replay_grade = 'N/A' replay_grade = 'N/A'
self.randomizer = Randomizer(false, nil) self.randomizer = Randomizer(false, nil)
self.input_playback = false self.input_playback = false
self.frames = 0 self.frames = 0
else else
@@ -64,22 +64,22 @@ function GameMode:new(player_name, input_file, replay_grade)
"9k", "8k", "7k", "6k", "5k", "4k", "3k", "2k", "1k", "9k", "8k", "7k", "6k", "5k", "4k", "3k", "2k", "1k",
"1D", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D" "1D", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D"
} }
self.promo_table = { self.promo_table = {
26666, 53333, 79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666, 26666, 53333, 79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666,
293333, 319999, 346666, 373333, 399999, 426666, 453333, 479999, 506666, 293333, 319999, 346666, 373333, 399999, 426666, 453333, 479999, 506666,
533333, 559999, 586666, 613333, 639999, 666666, 693333, 719999, 719999 533333, 559999, 586666, 613333, 639999, 666666, 693333, 719999, 719999
} }
self.autopromo_table = { self.autopromo_table = {
79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666, 293333, 319999, 79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666, 293333, 319999,
346666, 373333, 399999, 426666, 453333, 479999, 506666, 533333, 559999, 346666, 373333, 399999, 426666, 453333, 479999, 506666, 533333, 559999,
586666, 613333, 639999, 666666, 693333, 719999, 746666, 773333, 1000000 586666, 613333, 639999, 666666, 693333, 719999, 746666, 773333, 1000000
} }
self.demo_table = { self.demo_table = {
-1, 13332, 25000, 40000, 50000, 60000, 60000, 120000, 120000, 120000, -1, 13332, 25000, 40000, 50000, 60000, 60000, 120000, 120000, 120000,
180000, 180000, 240000, 240000, 300000, 300000, 360000, 360000, 360000, 180000, 180000, 240000, 240000, 300000, 300000, 360000, 360000, 360000,
420000, 420000, 480000, 480000, 480000, 480000, 540000, 540000, 540000 420000, 420000, 480000, 480000, 480000, 480000, 540000, 540000, 540000
} }
self.speed_divisor = 10000 self.speed_divisor = 10000
self.line_clear_flash = 0 self.line_clear_flash = 0
self.lines_cleared = 0 self.lines_cleared = 0
SOUNDS['bgm_firsthalf']:setVolume(0.3) SOUNDS['bgm_firsthalf']:setVolume(0.3)
@@ -89,7 +89,7 @@ function GameMode:new(player_name, input_file, replay_grade)
self.input_saved = false self.input_saved = false
self.end_grid_clear = false self.end_grid_clear = false
self.last_active = 0 self.last_active = 0
self.move_count = 0 self.move_count = 0
self.target = 0 self.target = 0
self.last_percent = 0 self.last_percent = 0
self.total_speed_loss = 0 self.total_speed_loss = 0
@@ -162,15 +162,15 @@ end
function GameMode:updateGradeHistory() function GameMode:updateGradeHistory()
if self.grade_score >= self.promo_table[self.grade] then if self.grade_score >= self.promo_table[self.grade] then
if (self.grade == 28 and self.grade_history[2] < 4) or self.grade < 28 then self.grade_history[2] = self.grade_history[2] + 1 end if (self.grade == 28 and self.grade_history[2] < 4) or self.grade < 28 then self.grade_history[2] = self.grade_history[2] + 1 end
self.point_flash = 60 self.point_flash = 60
self.point_flash_color = {0,1,0,1} self.point_flash_color = {0,1,0,1}
elseif self.grade_score <= self.demo_table[self.grade] then elseif self.grade_score <= self.demo_table[self.grade] then
if (self.grade == 1 and self.grade_history[2] > 0) or self.grade > 1 then self.grade_history[2] = self.grade_history[2] - 1 end if (self.grade == 1 and self.grade_history[2] > 0) or self.grade > 1 then self.grade_history[2] = self.grade_history[2] - 1 end
self.point_flash = 60 self.point_flash = 60
self.point_flash_color = {1,0,0,1} self.point_flash_color = {1,0,0,1}
end end
local auto_flag = false local auto_flag = false
while self.grade_score >= self.autopromo_table[self.grade] and self.grade < 28 do while self.grade_score >= self.autopromo_table[self.grade] and self.grade < 28 do
self.grade = self.grade + 1 self.grade = self.grade + 1
self.point_flash = 1 self.point_flash = 1
@@ -178,7 +178,7 @@ function GameMode:updateGradeHistory()
self.grade_change_color = {0,0,1,1} self.grade_change_color = {0,0,1,1}
self.end_game_sound = "autopromote" self.end_game_sound = "autopromote"
auto_flag = true auto_flag = true
end end
if self.grade_history[2] >= 5 and self.grade < 28 and auto_flag == false then if self.grade_history[2] >= 5 and self.grade < 28 and auto_flag == false then
self.grade = self.grade + 1 self.grade = self.grade + 1
self.point_flash = 1 self.point_flash = 1
@@ -194,7 +194,7 @@ function GameMode:updateGradeHistory()
end end
if self.starting_grade ~= self.grade then if self.starting_grade ~= self.grade then
self.grade_history[1] = self.grade self.grade_history[1] = self.grade
self.grade_history[2] = 2 self.grade_history[2] = 2
end end
self.grade_history[4] = self.grade_history[4] + 1 self.grade_history[4] = self.grade_history[4] + 1
end end
@@ -227,31 +227,31 @@ end
function GameMode:getARR() return 1 end function GameMode:getARR() return 1 end
function GameMode:getDropSpeed() return 1 end function GameMode:getDropSpeed() return 1 end
function GameMode:getARE() function GameMode:getARE()
if self.training then return 20 end if self.training then return 20 end
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][2] if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][2]
else return self.delay_table[#self.delay_table][2] end else return self.delay_table[#self.delay_table][2] end
end end
function GameMode:getLineARE() return self:getARE() end function GameMode:getLineARE() return self:getARE() end
function GameMode:getLockDelay() function GameMode:getLockDelay()
if self.training then return 99999999999 end if self.training then return 99999999999 end
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][3] if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][3]
else return self.delay_table[#self.delay_table][3] end else return self.delay_table[#self.delay_table][3] end
end end
function GameMode:getLineClearDelay() return self:getARE() end function GameMode:getLineClearDelay() return self:getARE() end
function GameMode:getDasLimit() function GameMode:getDasLimit()
if self.training then return 8 end if self.training then return 8 end
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][4] if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][4]
else return self.delay_table[#self.delay_table][4] end else return self.delay_table[#self.delay_table][4] end
end end
function GameMode:getDasCutDelay() return 0 end function GameMode:getDasCutDelay() return 0 end
function GameMode:getGravity() function GameMode:getGravity()
if self.training then return 20 end if self.training then return 20 end
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][1] if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][1]
else return self.delay_table[#self.delay_table][1] end else return self.delay_table[#self.delay_table][1] end
end end
@@ -346,8 +346,8 @@ function GameMode:update(inputs, ruleset)
if self.grade_change_flash > 0 and self.game_over_frames >= 2 then self.grade_change_flash = self.grade_change_flash - 1 end if self.grade_change_flash > 0 and self.game_over_frames >= 2 then self.grade_change_flash = self.grade_change_flash - 1 end
if self.point_flash > 0 and self.game_over_frames >= 2 then self.point_flash = self.point_flash - 1 end if self.point_flash > 0 and self.game_over_frames >= 2 then self.point_flash = self.point_flash - 1 end
if self.game_over_frames == 2 then if self.game_over_frames == 2 then
PlaySEOnce(self.end_game_sound) PlaySEOnce(self.end_game_sound)
end end
if self.game_over or self.completed then if self.game_over or self.completed then
self.game_over_frames = self.game_over_frames + 1 self.game_over_frames = self.game_over_frames + 1
if self.game_over_frames == 1 then self:storeInput(inputs) end if self.game_over_frames == 1 then self:storeInput(inputs) end
@@ -369,24 +369,24 @@ function GameMode:update(inputs, ruleset)
self.up_lock = true self.up_lock = true
end end
if not inputs["up"] then self.up_lock = false end if not inputs["up"] then self.up_lock = false end
local dir_list = {"down", "left", "right"} local dir_list = {"down", "left", "right"}
for i = 1, #dir_list do for i = 1, #dir_list do
if inputs[dir_list[i]] and not table.contains(self.directions_pressed, dir_list[i]) then if inputs[dir_list[i]] and not table.contains(self.directions_pressed, dir_list[i]) then
table.insert(self.directions_pressed, dir_list[i]) table.insert(self.directions_pressed, dir_list[i])
elseif not inputs[dir_list[i]] then elseif not inputs[dir_list[i]] then
for j=1, #self.directions_pressed do for j=1, #self.directions_pressed do
if self.directions_pressed[j] == dir_list[i] then table.remove(self.directions_pressed, j) end if self.directions_pressed[j] == dir_list[i] then table.remove(self.directions_pressed, j) end
end end
end end
end end
if #self.directions_pressed > 0 then if #self.directions_pressed > 0 then
for i=1, #self.directions_pressed-1 do for i=1, #self.directions_pressed-1 do
inputs[self.directions_pressed[i]] = false inputs[self.directions_pressed[i]] = false
end end
inputs[self.directions_pressed[#self.directions_pressed]] = true inputs[self.directions_pressed[#self.directions_pressed]] = true
if inputs['left'] then self.lastdir = -1 if inputs['left'] then self.lastdir = -1
elseif inputs['right'] then self.lastdir = 1 end elseif inputs['right'] then self.lastdir = 1 end
end end
-- advance one frame -- advance one frame
@@ -521,7 +521,7 @@ function GameMode:stackQualityCheck()
local stack_clean = self:detectHoles(x, y) local stack_clean = self:detectHoles(x, y)
if not stack_clean then if not stack_clean then
hole_num = hole_num + 1 hole_num = hole_num + 1
end end
end end
end end
end end
@@ -541,26 +541,26 @@ function GameMode:doStackQuality()
if total_speed <= 0 then total_speed = 0.001 end if total_speed <= 0 then total_speed = 0.001 end
self.total_speed_loss = total_speed / #self.speed_table self.total_speed_loss = total_speed / #self.speed_table
if #self.speed_table == 0 then self.total_speed_loss = 0 end if #self.speed_table == 0 then self.total_speed_loss = 0 end
self.last_holes = contiguous_holes self.last_holes = contiguous_holes
end end
function GameMode:doSpeedCheck() function GameMode:doSpeedCheck()
self.target = self.move_count self.target = self.move_count
local speed = (self.target/self.active_frames) local speed = (self.target/self.active_frames)
if speed > 1 then speed = 1 end if speed > 1 then speed = 1 end
table.insert(self.speed_table, 1, speed) table.insert(self.speed_table, 1, speed)
while #self.speed_table > 50 do while #self.speed_table > 50 do
table.remove(self.speed_table, #self.speed_table) table.remove(self.speed_table, #self.speed_table)
end end
local total_speed = 0 local total_speed = 0
for i=1, #self.speed_table do for i=1, #self.speed_table do
total_speed = total_speed + self.speed_table[i] total_speed = total_speed + self.speed_table[i]
end end
if total_speed <= 0 then total_speed = 0.001 end if total_speed <= 0 then total_speed = 0.001 end
self.total_speed_loss = total_speed / #self.speed_table self.total_speed_loss = total_speed / #self.speed_table
if #self.speed_table == 0 then self.total_speed_loss = 0 end if #self.speed_table == 0 then self.total_speed_loss = 0 end
self.last_active = self.active_frames self.last_active = self.active_frames
self.last_percent = speed self.last_percent = speed
self.active_frames = 0 self.active_frames = 0
self.move_count = 0 self.move_count = 0
end end
@@ -571,7 +571,7 @@ function GameMode:updateScore(cleared_lines)
while cleared_lines+self.total_lines > 300 do while cleared_lines+self.total_lines > 300 do
cleared_lines = cleared_lines - 1 cleared_lines = cleared_lines - 1
end end
self.last_speed = math.ceil(self.total_speed_loss * self.bonus_components['speed'] * cleared_lines) self.last_speed = math.ceil(self.total_speed_loss * self.bonus_components['speed'] * cleared_lines)
self.line_clear_flash = 240 self.line_clear_flash = 240
self.lines_cleared = cleared_lines self.lines_cleared = cleared_lines
self.score_to_add = self.lineClearPoints[cleared_lines] + self.last_speed self.score_to_add = self.lineClearPoints[cleared_lines] + self.last_speed
@@ -590,25 +590,25 @@ function GameMode:advanceOneFrame()
love.audio.stop() love.audio.stop()
self.audio_stopped = true self.audio_stopped = true
end end
end end
if self.training and not SOUNDS['bgm_title']:isPlaying() and SETTINGS["music"] then SOUNDS['bgm_title']:play() end if self.training and not SOUNDS['bgm_title']:isPlaying() and SETTINGS["music"] then SOUNDS['bgm_title']:play() end
if not self.training then if not self.training then
if self.nextbgmflag and SOUNDS['bgm_firsthalf']:isPlaying() then if self.nextbgmflag and SOUNDS['bgm_firsthalf']:isPlaying() then
if SOUNDS['bgm_firsthalf']:getVolume() > 0.1 then if SOUNDS['bgm_firsthalf']:getVolume() > 0.1 then
SOUNDS['bgm_firsthalf']:setVolume(SOUNDS['bgm_firsthalf']:getVolume()-0.01) SOUNDS['bgm_firsthalf']:setVolume(SOUNDS['bgm_firsthalf']:getVolume()-0.01)
else else
SOUNDS['bgm_firsthalf']:stop() SOUNDS['bgm_firsthalf']:stop()
end end
end end
if self.ready_frames < 1 and not SOUNDS['bgm_firsthalf']:isPlaying() and not SOUNDS['bgm_secondhalf']:isPlaying() and SETTINGS["music"] then if self.ready_frames < 1 and not SOUNDS['bgm_firsthalf']:isPlaying() and not SOUNDS['bgm_secondhalf']:isPlaying() and SETTINGS["music"] then
if not self.nextbgmflag then SOUNDS['bgm_firsthalf']:play() if not self.nextbgmflag then SOUNDS['bgm_firsthalf']:play()
elseif self.total_lines < 296 then SOUNDS['bgm_secondhalf']:play() end elseif self.total_lines < 296 then SOUNDS['bgm_secondhalf']:play() end
end end
if self.total_lines >= 296 then if self.total_lines >= 296 then
SOUNDS['bgm_firsthalf']:stop() SOUNDS['bgm_firsthalf']:stop()
SOUNDS['bgm_secondhalf']:stop() SOUNDS['bgm_secondhalf']:stop()
end end
end end
if self.clear then if self.clear then
self.completed = true self.completed = true
end end
@@ -637,29 +637,29 @@ end
function GameMode:onAttemptPieceMove(piece, grid) end function GameMode:onAttemptPieceMove(piece, grid) end
function GameMode:onAttemptPieceRotate(piece, grid) end function GameMode:onAttemptPieceRotate(piece, grid) end
function GameMode:onPieceMove(piece, grid, dx) function GameMode:onPieceMove(piece, grid, dx)
if not self.moved then if not self.moved then
self.move_count = self.move_count + 1 self.move_count = self.move_count + 1
self.moved = true self.moved = true
end end
end end
function GameMode:onPieceRotate(piece, grid, drot) function GameMode:onPieceRotate(piece, grid, drot)
if not self.moved then if not self.moved then
self.move_count = self.move_count + 1 self.move_count = self.move_count + 1
self.moved = true self.moved = true
end end
end end
function GameMode:onPieceDrop(piece, grid, dy) function GameMode:onPieceDrop(piece, grid, dy)
if not self.moved then if not self.moved then
self.move_count = self.move_count + 1 self.move_count = self.move_count + 1
self.moved = true self.moved = true
end end
end end
function GameMode:onPieceLock(piece, cleared_row_count) function GameMode:onPieceLock(piece, cleared_row_count)
if not self.moved then if not self.moved then
self.move_count = self.move_count + 1 self.move_count = self.move_count + 1
self.moved = true self.moved = true
end end
self.lastdir = 0 self.lastdir = 0
PlaySE("lock") PlaySE("lock")
end end
@@ -677,9 +677,10 @@ function GameMode:onPieceEnter()
end end
function GameMode:onGameOver() 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.input_playback and not self.training and not PENTO_MODE then
if not self.did_grades then if not self.did_grades then
self.grade_score = self.grade_score + self.speed_level self.grade_score = self.grade_score + self.speed_level
if #self.speed_table >= 49 then if #self.speed_table >= 49 then
self:updateGradeHistory() self:updateGradeHistory()
end end
@@ -689,16 +690,16 @@ function GameMode:onGameOver()
end end
self:drawEndScoringInfo() self:drawEndScoringInfo()
elseif not self.did_grades then elseif not self.did_grades then
self.grade_score = self.grade_score + self.speed_level self.grade_score = self.grade_score + self.speed_level
self.did_grades = true self.did_grades = true
end end
if PENTO_MODE and not self.training then self:drawEndScoringInfo() end if PENTO_MODE and not self.training then self:drawEndScoringInfo() end
end end
function GameMode:drawEndScoringInfo() function GameMode:drawEndScoringInfo()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
drawText("Score: ", 247, 135, 1000, "left") drawText("Score: ", 247, 135, 1000, "left")
drawBigText(string.format("%s", self.grade_score), 247, 150, 100, "center") drawBigText(string.format("%s", self.grade_score), 247, 150, 100, "center")
if not PENTO_MODE then if not PENTO_MODE then
drawText("Best scores:", 247, 220, 1000, "left") drawText("Best scores:", 247, 220, 1000, "left")
@@ -868,10 +869,10 @@ function GameMode:drawLineClearAnimation()
fade_timer = self.lcd/20 fade_timer = self.lcd/20
love.graphics.setColor(1,1,1,fade_timer) love.graphics.setColor(1,1,1,fade_timer)
love.graphics.draw(BLOCKS[block.skin][block.colour..'_d'], real_x, real_y+fall_timer) love.graphics.draw(BLOCKS[block.skin][block.colour..'_d'], real_x, real_y+fall_timer)
if self.lcd > self:getLineClearDelay() - 5 then if self.lcd > self:getLineClearDelay() - 5 then
love.graphics.setColor(1,1,1,fade_timer*0.3) love.graphics.setColor(1,1,1,fade_timer*0.3)
love.graphics.draw(BLOCKS[block.skin]['W'], real_x, real_y+fall_timer) love.graphics.draw(BLOCKS[block.skin]['W'], real_x, real_y+fall_timer)
end end
end end
end end
end end
@@ -920,61 +921,61 @@ function GameMode:drawGrid()
end end
function GameMode:drawInputDisplay(left, top) function GameMode:drawInputDisplay(left, top)
if self.replay_inputs[self.frames] ~= nil then if self.replay_inputs[self.frames] ~= nil then
drawText("+", left+10, top+8, 1000, "left") drawText("", left+7.5, top+ 8, 1000, "left")
drawText("", left+10, top+18, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['down']),1,1-boolToInt(self.replay_inputs[self.frames]['down']),1}) drawText(CHAR.key.down , left+ 5, top+18, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['down']),1,1-boolToInt(self.replay_inputs[self.frames]['down']),1})
drawText("", left, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['left']),1,1-boolToInt(self.replay_inputs[self.frames]['left']),1}) drawText(CHAR.key.left , left- 5, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['left']),1,1-boolToInt(self.replay_inputs[self.frames]['left']),1})
drawText("", left+20, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['right']),1,1-boolToInt(self.replay_inputs[self.frames]['right']),1}) drawText(CHAR.key.right, left+ 15, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['right']),1,1-boolToInt(self.replay_inputs[self.frames]['right']),1})
drawText("L", left+35, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1}) drawText("L", left+ 35, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1})
drawText("R", left+50, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1}) drawText("R", left+ 50, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1})
drawText("L", left+65, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1}) drawText("L", left+ 65, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1})
drawText("R", left+80, top+8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1}) drawText("R", left+ 80, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1})
else else
drawText("+", left+10, top+8, 1000, "left") drawText("" , left+7.5, top+ 8, 1000, "left")
drawText("", left+10, top+18, 1000, "left") drawText(CHAR.key.down , left+ 5, top+18, 1000)
drawText("", left, top+8, 1000, "left") drawText(CHAR.key.left , left- 5, top+ 8, 1000)
drawText("", left+20, top+8, 1000, "left") drawText(CHAR.key.right, left+ 15, top+ 8, 1000)
drawText("L", left+35, top+8, 1000, "left") drawText("L" , left+ 35, top+ 8, 1000, "left")
drawText("R", left+50, top+8, 1000, "left") drawText("R" , left+ 50, top+ 8, 1000, "left")
drawText("L", left+65, top+8, 1000, "left") drawText("L" , left+ 65, top+ 8, 1000, "left")
drawText("R", left+80, top+8, 1000, "left") drawText("R" , left+ 80, top+ 8, 1000, "left")
end end
end end
function GameMode:drawSpeedStats(left, top) function GameMode:drawSpeedStats(left, top)
love.graphics.setColor(0,0,0,0.5) love.graphics.setColor(0,0,0,0.5)
love.graphics.rectangle("fill", left+3, top+3, 190, 145, 10, 10) love.graphics.rectangle("fill", left+3, top+3, 190, 145, 10, 10)
love.graphics.setColor(0.05,0.05,0.05,1) love.graphics.setColor(0.05,0.05,0.05,1)
love.graphics.rectangle("fill", left, top, 190, 145, 10, 10) love.graphics.rectangle("fill", left, top, 190, 145, 10, 10)
drawText("Efficiency Bonus: ", left+15, top+10, 1000, "left") drawText("Efficiency Bonus: ", left+15, top+5, 1000, "left")
local lines = self.total_lines local lines = self.total_lines
if lines == 0 then lines = 1 end if lines == 0 then lines = 1 end
if self.move_count == 0 then if self.move_count == 0 then
drawText(string.format(" %4d Num. of Moves", self.target), left+15, top+25, 1000, "left") drawText(string.format(" %4d Num. of Moves", self.target), left+15, top+20, 1000, "left")
else else
drawText(string.format(" %4d Num. of Moves", self.move_count), left+15, top+25, 1000, "left") drawText(string.format(" %4d Num. of Moves", self.move_count), left+15, top+20, 1000, "left")
end end
drawText(string.format("/ %4d Active Frames", self.last_active), left+15, top+40, 1000, "left") drawText(string.format("/ %4d Active Frames", self.last_active), left+15, top+35, 1000, "left")
drawText(string.format("= %1.2f\n (0 added for hole)\n %1.2f %dpc Average\nx %s x Lines\n+ %4d", self.last_percent, self.total_speed_loss, #self.speed_table, self.bonus_components['speed'], self.last_speed), left+15, top+55, 1000, "left") drawText(string.format("= %1.2f\n (0 added for hole)\n %1.2f %dpc Average\nx %s x Lines\n+ %4d", self.last_percent, self.total_speed_loss, #self.speed_table, self.bonus_components['speed'], self.last_speed), left+15, top+50, 1000, "left")
end end
function GameMode:drawLinesStats(left, top) function GameMode:drawLinesStats(left, top)
love.graphics.setColor(0,0,0,0.5) love.graphics.setColor(0,0,0,0.5)
love.graphics.rectangle("fill", left+3, top+3, 190, 90, 10, 10) love.graphics.rectangle("fill", left+3, top+3, 190, 90, 10, 10)
love.graphics.setColor(0.05,0.05,0.05,1) love.graphics.setColor(0.05,0.05,0.05,1)
love.graphics.rectangle("fill", left, top, 190, 90, 10, 10) love.graphics.rectangle("fill", left, top, 190, 90, 10, 10)
local lines = self.total_lines local lines = self.total_lines
if lines == 0 then lines = 1 end if lines == 0 then lines = 1 end
drawText("Lines Bonus: ", left+15, top+10, 1000, "left") drawText("Lines Bonus: ", left+15, top+10, 1000, "left")
-- drawText(string.format("+ %4d %3d%%", self.lineClearPoints[self.lines_cleared], (self.score_totals['lines']/(self.lineClearPoints[4]*math.ceil(lines/4)))*100), left+15, top+25, 1000, "left") -- drawText(string.format("+ %4d %3d%%", self.lineClearPoints[self.lines_cleared], (self.score_totals['lines']/(self.lineClearPoints[4]*math.ceil(lines/4)))*100), left+15, top+25, 1000, "left")
drawText(string.format("2 x Lines = %d\n3 x Lines = %d\n4 x Lines = %d", self.lineClearPoints[2], self.lineClearPoints[3], self.lineClearPoints[4]), left+15, top+25, 1000, "left") drawText(string.format("2 x Lines = %d\n3 x Lines = %d\n4 x Lines = %d", self.lineClearPoints[2], self.lineClearPoints[3], self.lineClearPoints[4]), left+15, top+25, 1000, "left")
end end
function GameMode:drawScoringInfo() function GameMode:drawScoringInfo()
-- Name & Grade -- Name & Grade
love.graphics.setColor(0,0,0,0.5) love.graphics.setColor(0,0,0,0.5)
love.graphics.rectangle("fill", 98, 83, 110, 180, 10, 10) love.graphics.rectangle("fill", 98, 83, 110, 180, 10, 10)
love.graphics.setColor(0.05,0.05,0.05,1) love.graphics.setColor(0.05,0.05,0.05,1)
love.graphics.rectangle("fill", 95, 80, 110, 180, 10, 10) love.graphics.rectangle("fill", 95, 80, 110, 180, 10, 10)
if not PENTO_MODE then drawText("Grade:", 100, 128, 1000, "left") end if not PENTO_MODE then drawText("Grade:", 100, 128, 1000, "left") end
-- Line & Level -- Line & Level
@@ -987,46 +988,46 @@ function GameMode:drawScoringInfo()
end end
-- REPLAY -- REPLAY
if self.input_playback then if self.input_playback then
love.graphics.setColor(0,0,0,0.5) love.graphics.setColor(0,0,0,0.5)
love.graphics.rectangle("fill", 68, 270, 140, 190, 10, 10) love.graphics.rectangle("fill", 68, 270, 140, 190, 10, 10)
love.graphics.setColor(0.05,0.05,0.05,1) love.graphics.setColor(0.05,0.05,0.05,1)
love.graphics.rectangle("fill", 65, 267, 140, 190, 10, 10) love.graphics.rectangle("fill", 65, 267, 140, 190, 10, 10)
drawText(string.format("Replay in progress\n\n\n\n\n\n\n\n\n%s", formatTime(self.frames)), 70, 275, 1000, "left") drawBoldText(string.format("REPLAY IN PROGRESS\n\n\n\n\n\n\n\n\n%s", formatTime(self.frames)), 70, 275, 1000, "left")
drawBigText(string.format("%s", self.grade), 100, 143, 1000, "left") drawBigText(string.format("%s", self.grade), 100, 143, 1000, "left")
self:drawInputDisplay(103,185) self:drawInputDisplay(103,185)
elseif not PENTO_MODE then elseif not PENTO_MODE then
if math.mod(self.grade_change_flash, 5) ~= 0 then if math.mod(self.grade_change_flash, 5) ~= 0 then
drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left", self.grade_change_color) drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left", self.grade_change_color)
else else
drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left") drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left")
end end
local points_text = nil local points_text = nil
if self.grade == 1 and self.grade_history[2] == 2 then if self.grade == 1 and self.grade_history[2] == 2 then
points_text = " |.." points_text = " |.."
elseif self.grade == 1 and self.grade_history[2] == 3 then elseif self.grade == 1 and self.grade_history[2] == 3 then
points_text = " .|." points_text = " .|."
elseif self.grade == 1 and self.grade_history[2] == 4 then elseif self.grade == 1 and self.grade_history[2] == 4 then
points_text = " ..|" points_text = " ..|"
elseif self.grade_history[2] == 0 then elseif self.grade_history[2] == 0 then
points_text = "|...." points_text = "|...."
elseif self.grade_history[2] == 1 then elseif self.grade_history[2] == 1 then
points_text = ".|..." points_text = ".|..."
elseif self.grade_history[2] == 2 then elseif self.grade_history[2] == 2 then
points_text = "..|.." points_text = "..|.."
elseif self.grade_history[2] == 3 then elseif self.grade_history[2] == 3 then
points_text = "...|." points_text = "...|."
elseif self.grade_history[2] == 4 then elseif self.grade_history[2] == 4 then
points_text = "....|" points_text = "....|"
end end
if self.grade > 1 then points_text = '-'..points_text if self.grade > 1 then points_text = '-'..points_text
else points_text = ' '..points_text end else points_text = ' '..points_text end
if self.grade < 28 then points_text = points_text..'+' end if self.grade < 28 then points_text = points_text..'+' end
drawText("Promotion\nMeter:", 100, 174, 1000, "left") drawText("Promotion\nMeter:", 100, 174, 1000, "left")
if self.point_flash > 0 then if self.point_flash > 0 then
drawBigText(points_text, 100, 208, 1000, "left", self.point_flash_color) drawBigText(points_text, 100, 208, 1000, "left", self.point_flash_color)
else else
drawBigText(points_text, 100, 208, 1000, "left") drawBigText(points_text, 100, 208, 1000, "left")
end end
end end
if (self.game_over or self.completed) and self.game_over_frames <= 50 and not self.input_playback and not self.training and not PENTO_MODE then if (self.game_over or self.completed) and self.game_over_frames <= 50 and not self.input_playback and not self.training and not PENTO_MODE then
drawText("SAVING, PLEASE WAIT", 232, 460, 1000, "left") drawText("SAVING, PLEASE WAIT", 232, 460, 1000, "left")
@@ -1035,8 +1036,8 @@ function GameMode:drawScoringInfo()
drawBigText(self.player_name:upper(), 100, 98, 1000, "left") drawBigText(self.player_name:upper(), 100, 98, 1000, "left")
drawText("Ver. 2", 550, 435, 1000, "left") drawText("Ver. 2", 550, 435, 1000, "left")
if self.input_playback then if self.input_playback then
self:drawSpeedStats(385, 99) self:drawSpeedStats(385, 99)
self:drawLinesStats(385, 251) self:drawLinesStats(385, 251)
love.graphics.setColor(0,0,0,0.5) love.graphics.setColor(0,0,0,0.5)
love.graphics.rectangle("fill", 385+3, 348+3, 190, 50, 10, 10) love.graphics.rectangle("fill", 385+3, 348+3, 190, 50, 10, 10)
love.graphics.setColor(0.05,0.05,0.05,1) love.graphics.setColor(0.05,0.05,0.05,1)
@@ -1065,17 +1066,17 @@ function GameMode:drawBackground()
if BACKGROUNDS[bg]:tell() >= limit then if BACKGROUNDS[bg]:tell() >= limit then
BACKGROUNDS[bg]:rewind() BACKGROUNDS[bg]:rewind()
end end
if bg == 0 or bg == 8 or bg == 9 or bg == 3 then brightness = 0.7 end if bg == 0 or bg == 8 or bg == 9 or bg == 3 then brightness = 0.7 end
love.graphics.setColor(brightness, brightness, brightness, 1) love.graphics.setColor(brightness, brightness, brightness, 1)
love.graphics.draw(BACKGROUNDS[bg]) love.graphics.draw(BACKGROUNDS[bg])
end end
function GameMode:drawFrame() function GameMode:drawFrame()
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))
love.graphics.line(216,80+(16*self.grid.height),216+(16*self.grid.width),80+(16*self.grid.height)) love.graphics.line(216,80+(16*self.grid.height),216+(16*self.grid.width),80+(16*self.grid.height))
love.graphics.line(216,80,216+(16*self.grid.width),80) love.graphics.line(216,80,216+(16*self.grid.width),80)
love.graphics.setColor(0, 0, 0, 1) love.graphics.setColor(0, 0, 0, 1)
love.graphics.rectangle( love.graphics.rectangle(
"fill", 216, 80, "fill", 216, 80,

View File

@@ -64,7 +64,7 @@ function control_type.button:new(data)
r=data.r or 80, -- size r=data.r or 80, -- size
shape=data.shape or 'circle', shape=data.shape or 'circle',
key=data.key or 'X', key=data.key or 'X',
iconSize=data.iconSize or 80, iconSize=data.iconSize or 60,
alpha=data.alpha or 0.75, alpha=data.alpha or 0.75,
quad=virtual_quad[data.key] quad=virtual_quad[data.key]
},self) },self)
@@ -148,6 +148,7 @@ local touches={}
local global_toggle=false local global_toggle=false
VCTRL={} VCTRL={}
VCTRL.focus=nil -- Focusing buttons VCTRL.focus=nil -- Focusing buttons
VCTRL.hasChanged = false
---@class VCTRL.data ---@class VCTRL.data
---@field type 'button' ---@field type 'button'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -1,7 +1,8 @@
-- SIMPLE-BUTTON.lua -- SIMPLE-BUTTON.lua<br>
-- A simple module that aims to help you quickly create buttons -- A simple module that aims to help you quickly create buttons<br>
-- It is can be used as a base class to help you quickly creating button -- It is can be used as a base class to help you quickly creating button<br>
-- This module has type notations so IntelliSense should give you some suggestions -- This module has type notations so IntelliSense should give you some suggestions<br>
local BUTTON = {}
-- MIT License -- MIT License
@@ -174,9 +175,6 @@ function button:release(x, y, touchID)
end end
end end
local BUTTON = {}
---@param D BUTTON.button|BUTTON.newData ---@param D BUTTON.button|BUTTON.newData
---@param safe? boolean @ Creating widget? If not then ignore accept missing important parameters ---@param safe? boolean @ Creating widget? If not then ignore accept missing important parameters
---@return nil ---@return nil

View File

@@ -1,6 +1,12 @@
-- Fonts -- Fonts
FONT_tromi = love.graphics.newFont('res/fonts/monofonto rg.otf', 28) FONT_tromi = love.graphics.newFont('res/fonts/Iosevka-Bold.ttf' , 28)
FONT_big = love.graphics.newFont('res/fonts/monofonto rg.otf', 56) FONT_big = love.graphics.newFont('res/fonts/Iosevka-Heavy.ttf', 56)
FONT_bold = love.graphics.newFont('res/fonts/Iosevka-Heavy.ttf', 28)
-- Icons
FONT_tromi:setFallbacks(love.graphics.newFont('res/fonts/techmino_proportional.otf', 28))
FONT_bold :setFallbacks(love.graphics.newFont('res/fonts/techmino_proportional.otf', 28))
FONT_big :setFallbacks(love.graphics.newFont('res/fonts/techmino_proportional.otf', 56))
CHAR = require("char")
local font_height = FONT_tromi:getHeight() * 0.5 local font_height = FONT_tromi:getHeight() * 0.5
local font_big_height = FONT_big:getHeight() * 0.5 local font_big_height = FONT_big:getHeight() * 0.5
@@ -15,7 +21,7 @@ BUTTON = require "libs.simple-button"
BUTTON.setDefaultOption{ BUTTON.setDefaultOption{
draw = function(self) draw = function(self)
local need_big_font = (self.font == FONT_big) local need_big_font = (self.font == FONT_big)
love.graphics.setColor(self.backgroundColor) love.graphics.setColor(self.backgroundColor)
love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r) love.graphics.rectangle('fill', self.x, self.y, self.w, self.h, self.r)
@@ -31,22 +37,19 @@ BUTTON.setDefaultOption{
local lineAmount local lineAmount
do do
local _, t local _, t = self.font:getWrap(text, (self.w - 5) * 2)
if need_big_font then
_, t = FONT_big:getWrap(text, (self.w - 5) * 2)
else
_, t = FONT_tromi:getWrap(text, (self.w - 5) * 2)
end
lineAmount = #t lineAmount = #t
end end
local _font_height = need_big_font and font_big_height or font_height local _font_height = need_big_font and font_big_height or font_height
local textHeight = _font_height * (lineAmount * 0.5) local textHeight = _font_height * (lineAmount * 0.5)
local textPos = self.y + (self.h * 0.5) - textHeight local textPos = self.y + (self.h * 0.5) - textHeight
if need_big_font then if self.font == FONT_big then
drawBigText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor) drawBigText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor)
elseif self.font == FONT_bold then
drawBoldText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor)
else else
drawText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor) drawText(text, self.x + 2.5, textPos, self.w - 5, self.textOrientation, self.textColor)
end end

View File

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

View File

@@ -35,6 +35,7 @@ function SCENE:onInputPress(e) end
function SCENE:onInputRelease(e) end function SCENE:onInputRelease(e) end
GameScene = require "scene.game" GameScene = require "scene.game"
TrainingScene = require "scene.training"
NameEntryScene = require "scene.name_entry" NameEntryScene = require "scene.name_entry"
KeyConfigScene = require "scene.key_config" KeyConfigScene = require "scene.key_config"
@@ -44,7 +45,7 @@ TouchConfigPreviewScene = require "scene.touch_config_preview"
InputConfigScene = require "scene.input_config" InputConfigScene = require "scene.input_config"
ReplaySelectScene = require "scene.replay" ReplaySelectScene = require "scene.replay"
TrainingScene = require "scene.training" ReplayTestScene = require"scene.replay_test"
FullscreenScene = require "scene.fullscreen" FullscreenScene = require "scene.fullscreen"
MusicToggleScene = require "scene.music_toggle" MusicToggleScene = require "scene.music_toggle"

BIN
res/fonts/Iosevka-Bold.ttf Normal file

Binary file not shown.

BIN
res/fonts/Iosevka-Heavy.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -45,6 +45,8 @@ local buttonList = {
local menuKey -- MENU key used to go main menu XD local menuKey -- MENU key used to go main menu XD
function GameScene:new(player_name, replay_file, replay_grade) function GameScene:new(player_name, replay_file, replay_grade)
VCTRL[9].show = false
menuKey = BUTTON.new{ menuKey = BUTTON.new{
text = "MENU", text = "MENU",
x = 265, y = 0, w = 60, h = 25, x = 265, y = 0, w = 60, h = 25,
@@ -130,7 +132,7 @@ end
function GameScene:onInputPress(e) function GameScene: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
BUTTON.press(buttonList, e.x, e.y, e.id) if self.game.input_playback then BUTTON.press(buttonList, e.x, e.y, e.id) end
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_decide" or e.input == "menu_back" or e.input == "rotate_right") and self.game.game_over_frames > 50 then
SCENE = TitleScene() SCENE = TitleScene()
@@ -171,7 +173,7 @@ end
function GameScene:onInputRelease(e) function GameScene:onInputRelease(e)
if e.type == "mouse" or (e.type == "touch" and not VCTRL.release(e.id)) then if e.type == "mouse" or (e.type == "touch" and not VCTRL.release(e.id)) then
BUTTON.release(buttonList, e.x, e.y, e.id) if self.game.input_playback then BUTTON.release(buttonList, e.x, e.y, e.id) end
menuKey:release(e.x, e.y, e.id) menuKey:release(e.x, e.y, e.id)
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = false self.inputs[e.input] = false

View File

@@ -47,7 +47,7 @@ local function updateButtonList(self)
if not SETTINGS.firstTime then if not SETTINGS.firstTime then
menu_screens[4] = TitleScene menu_screens[4] = TitleScene
buttonList[4] = BUTTON.new{ buttonList[4] = BUTTON.new{
text = "", font = FONT_big, text = CHAR.icon.home, font = FONT_big,
x = 75, y = 280, w = 40, h = 40, x = 75, y = 280, w = 40, h = 40,
codeWhenReleased = function() codeWhenReleased = function()
if self.menu_state ~= 4 then if self.menu_state ~= 4 then
@@ -70,7 +70,7 @@ function ConfigScene:new(first_time)
updateButtonList(self) updateButtonList(self)
secret_code_used = false 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 self.menu_state = 1
if first_time then if first_time then
@@ -88,10 +88,10 @@ function ConfigScene:render()
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 - Right 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 - Down 9 - Rotate right 2", 80, 350, 1000
) )
else else
@@ -128,7 +128,7 @@ function ConfigScene:onInputMove(e)
end end
---@param key string ---@param key string
local function checkSecretCodeInput(self, key) 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))
@@ -160,7 +160,7 @@ local function checkSecretCodeInput(self, key)
SETTINGS.firstTime = false SETTINGS.firstTime = false
SETTINGS.tvMode = true SETTINGS.tvMode = true
secret_code_used = true secret_code_used = true
updateButtonList(self) updateButtonList(SCENE)
elseif current_code == "........" then elseif current_code == "........" then
SETTINGS.input.keys = {} SETTINGS.input.keys = {}
SETTINGS.tvMode = false SETTINGS.tvMode = false
@@ -183,7 +183,7 @@ function ConfigScene:onInputPress(e)
) then ) then
SCENE = TitleScene() SCENE = TitleScene()
end end
checkSecretCodeInput(self, e.key or "") checkSecretCodeInput(e.key or "")
end end
function ConfigScene:onInputRelease(e) function ConfigScene:onInputRelease(e)
if e.type == "touch" or e.type == "mouse" then if e.type == "touch" or e.type == "mouse" then

View File

@@ -4,29 +4,41 @@ ReplaySelectScene.title = "Replay"
local replay_list local replay_list
local buttonList = { local buttonList = {
BUTTON.new{ BUTTON.new{
text = "\nUP", font = FONT_big, text = CHAR.key.up.."\nUP", font = FONT_big,
x = 425, y = 80, w = 80, h = 80, x = 425, y = 80, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "up"} end, codeWhenPressed = function() SCENE:onInputPress {input = "up"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "up"} end codeWhenReleased = function() SCENE:onInputRelease{input = "up"} end
}, },
BUTTON.new{ BUTTON.new{
text = "\nDOWN", font = FONT_big, text = CHAR.key.down.."\nDOWN", font = FONT_big,
x = 425, y = 240, w = 80, h = 80, x = 425, y = 240, w = 80, h = 80,
codeWhenPressed = function() SCENE:onInputPress {input = "down"} end, codeWhenPressed = function() SCENE:onInputPress {input = "down"} end,
codeWhenReleased = function() SCENE:onInputRelease{input = "down"} end codeWhenReleased = function() SCENE:onInputRelease{input = "down"} end
}, },
BUTTON.new{ BUTTON.new{
text = "\nPLAY", font = FONT_big, text = CHAR.icon.play.."\nPLAY", font = FONT_big,
x = 345, y = 160, w = 80, h = 80, x = 345, y = 160, w = 80, h = 80,
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 = "\nHOME", font = FONT_big, text = CHAR.icon.home.."\nHOME", font = FONT_big,
x = 505, y = 160, w = 80, h = 80, x = 505, y = 160, w = 80, h = 80,
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{
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
},
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
},
} }
function ReplaySelectScene:new() function ReplaySelectScene:new()
@@ -135,7 +147,7 @@ function ReplaySelectScene:onInputPress(e)
if e.type == "touch" or e.type == "mouse" then if e.type == "touch" or e.type == "mouse" then
BUTTON.press(buttonList, e.x, e.y, e.id) 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 if self.replays[1] == nil then SCENE = TitleScene(); return
else else
local line_components = {} local line_components = {}
@@ -146,15 +158,30 @@ function ReplaySelectScene:onInputPress(e)
local player_grade = string.gsub(line_components[2], " ", "") local player_grade = string.gsub(line_components[2], " ", "")
SCENE = GameScene(player_name, selected_replay, player_grade) SCENE = GameScene(player_name, selected_replay, player_grade)
end end
-- elseif e.input == "rotate_right" then -- Will add in future, not now elseif e.input == "rotate_left" then -- Export
-- love.system.setClipboardText(love.data.encode("string", "base64", love.filesystem.read('saves/replays/'..selected_replay))) 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 elseif e.input == "up" or e.scancode == "up" then
if self.replays[1] == nil then SCENE = TitleScene(); return end if self.replays[1] == nil then SCENE = TitleScene(); return end
self.direction = 'up' self.direction = 'up'
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 == "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() SCENE = TitleScene()
end end
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:onInputPress()
SCENE = ReplaySelectScene()
end
return ReplayTestScene

View File

@@ -15,6 +15,8 @@ local main_menu_screens = {
} }
function TitleScene:new() function TitleScene:new()
VCTRL.clearAll() -- Reset the RESTART button state
VCTRL.new(SETTINGS.input.virtual)
if SOUNDS['bgm_firsthalf']:isPlaying() or SOUNDS['bgm_secondhalf']:isPlaying() or not SETTINGS["music"] then if SOUNDS['bgm_firsthalf']:isPlaying() or SOUNDS['bgm_secondhalf']:isPlaying() or not SETTINGS["music"] then
love.audio.stop() love.audio.stop()
end end

View File

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

View File

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

View File

@@ -57,6 +57,8 @@ function TrainingScene:onInputPress(e)
SCENE = TitleScene() SCENE = TitleScene()
elseif (e.input == "menu_back") then elseif (e.input == "menu_back") then
SCENE = TitleScene() SCENE = TitleScene()
elseif e.input == "restart" or e.input == "menu_decide" then
SCENE = TrainingScene()
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = true self.inputs[e.input] = true
end end

View File

@@ -25,15 +25,14 @@ local _defaultSettings = {
{type='button',x=640-145,y=355,key= 'rotate_left2',r=45,iconSize=60,alpha=0.4}, {type='button',x=640-145,y=355,key= 'rotate_left2',r=45,iconSize=60,alpha=0.4},
{type='button',x=640- 70,y=430,key= 'rotate_right',r=45,iconSize=60,alpha=0.4}, {type='button',x=640- 70,y=430,key= 'rotate_right',r=45,iconSize=60,alpha=0.4},
{type='button',x=640- 70,y=280,key='rotate_right2',r=45,iconSize=60,alpha=0.4}, {type='button',x=640- 70,y=280,key='rotate_right2',r=45,iconSize=60,alpha=0.4},
{type='button',x=320- 40,y=420,key= 'menu_decide',r=35,iconSize=60,alpha=0.4}, {type='button',x=320, y=420,key= 'restart',r=35,iconSize=60,alpha=0.4},
{type='button',x=320+ 40,y=420,key= 'menu_back',r=35,iconSize=60,alpha=0.4},
} }
}, },
tvMode = false -- 79338732 tvMode = false
} }
SETTINGS = setmetatable( SETTINGS = setmetatable(
{}, {__default__ = _defaultSettings},
{ {
__index = function(_, k) __index = function(_, k)
if _settings[k] == nil then if _settings[k] == nil then