diff --git a/Zenitha b/Zenitha index cc97026e..0c09d880 160000 --- a/Zenitha +++ b/Zenitha @@ -1 +1 @@ -Subproject commit cc97026e5c8dbcdecdf3c0731c34ccd463b1e720 +Subproject commit 0c09d880bd5aeeb8d0c06f724d3ab0e664a8e3f1 diff --git a/assets/finalwarning.png b/assets/finalwarning.png new file mode 100644 index 00000000..9f969cd9 Binary files /dev/null and b/assets/finalwarning.png differ diff --git a/data/achievement.lua b/data/achievement.lua index e8ff5484..d4696547 100644 --- a/data/achievement.lua +++ b/data/achievement.lua @@ -587,7 +587,7 @@ local d = { quote = [[Put your blood, sweat, and tears into the climb, or fall.]], credit = "@Tizago", rank = floorRank(1, 3, 4, 5, 6, 7, 8), - hide = function() return GAME.completion.EX == 0 end, + hide = function() return GAME.completion.EX == 0 or GAME.completion.VL == 0 end, }, { -- ASGVrDPrMS ex = true, @@ -707,7 +707,7 @@ local d = { ex = true, id = 'the_unreliable_one', name = "The Unreliable One", - desc = [[Highest amount of KILLs in a single reversed Duo run]], + desc = [[Highest amount of KILLs in a single reversed "Duo" run]], quote = [["I'll never let you off."]], scoreSimp = function(kill) return kill .. " Kills" end, rank = numberRank(0, 2, 3, 4, 5, 6, 8), @@ -870,7 +870,7 @@ local d = { ex = true, id = 'zero_to_sixty', name = "Zero-to-sixty", - desc = [[Fastest time to reach Gigaspeed using NH rVL AS]], + desc = [[Fastest time to reach GIGASPEED using NH rVL AS]], quote = [["Didn't even need the 1-foot rollout!"]], comp = '<', credit = "@FCSplayz", @@ -886,6 +886,7 @@ local d = { quote = [[Three steps forward, two steps back. Six steps forward, five steps back.]], scoreSimp = function(kill) return kill .. " Entries" end, rank = numberRank(0, 2, 3, 3, 4, 4, 5), + hide = function() return STAT.totalGiga == 0 end, }, { -- under_the_radar ex = true, @@ -914,7 +915,7 @@ local d = { quote = [[Excessive restraint can make one deeply entangled in it.]], comp = '<', scoreSimp = function(flip) return floor(flip) .. " Flips" end, - rank = numberRankRev(90, 86, 84, 82, 80, 77, 74), + rank = numberRankRev(100, 88, 85, 82, 80, 78, 74), hide = function() return GAME.completion.NH == 0 end, }, { -- detail_oriented @@ -2157,7 +2158,7 @@ local d = { { -- music_man (1.1.2) id = 'music_man', name = "Music Man!!!", - desc = [[Enable the Music Player in ZCEM]], + desc = [[Access the Music Player via ZCEM]], quote = [["Wait, why is "GAME PLAY" a button? Also, isn't it just one word?"]], credit = "@TrevorSmithy", hide = TRUE, diff --git a/data/combo.lua b/data/combo.lua index 8365ce5b..84a1465c 100644 --- a/data/combo.lua +++ b/data/combo.lua @@ -449,6 +449,7 @@ d.gameEX = { { set = "EX NH GV VL DH", name = "The Veteran" }, { set = "EX NH GV VL IN", name = "Foresight" }, { set = "EX NH GV VL AS", name = "Recursion of Death" }, + { set = "EX NH GV VL DP", name = "Quadruple Maxout" }, { set = "EX NH GV DH IN", name = "Readlock" }, { set = "EX NH GV DH AS", name = "The Kill Screen" }, { set = "EX NH GV DH DP", name = "The hanged down pair" }, @@ -492,9 +493,10 @@ d.gameEX = { { set = "EX GV DH AS DP", name = "Omni Spinners" }, { set = "EX GV IN AS DP", name = "Masterclass" }, { set = "EX VL DH IN AS", name = "Reverse Quintuple Threat" }, + { set = "EX VL DH IN DP", name = "False Allies" }, { set = "EX VL DH AS DP", name = "Hello BPM Year" }, { set = "EX VL IN AS DP", name = "Oblivious Spider" }, - { set = "EX DH IN AS DP", name = "Lost and Forgotten" }, + { set = "EX DH IN AS DP", name = "Professional Bodybuilder" }, { set = "NH MS GV VL DH", name = "Quintuple threat" }, { set = "NH MS GV VL IN", name = "The Guardian of Change" }, { set = "NH MS GV VL AS", name = "Dreadlock" }, @@ -515,7 +517,7 @@ d.gameEX = { { set = "NH GV VL DH AS", name = "Demonic Possession" }, { set = "NH GV VL DH DP", name = "Duality" }, { set = "NH GV VL IN AS", name = "Ergosphere" }, - { set = "NH GV VL IN DP", name = "Abysmal Connection" }, + { set = "NH GV VL IN DP", name = "Dual Black Hole System" }, { set = "NH GV VL AS DP", name = "Forced Evolution" }, { set = "NH GV DH IN AS", name = "Cheat Code" }, { set = "NH GV DH IN DP", name = "Living in the Past" }, diff --git a/data/devcommentary.lua b/data/devcommentary.lua index 6c43db79..1fd15c36 100644 --- a/data/devcommentary.lua +++ b/data/devcommentary.lua @@ -408,7 +408,7 @@ return { I guess I'll have to just keep on going, pulling myself forward. If I wait around too long, I'll never get anything done. ]], ['eEX rNH rMS rGV eVL rDH rIN eAS rDP'] = STRING.trimIndent [[ - The Overwhelemed Smithy, because, well, I'm Trevor Smithy and I feel like I get overwhelmed easily. + The Overwhelmed Smithy, because, well, I'm Trevor Smithy and I feel like I get overwhelmed easily. Too many things happening at once, too many conditions to handle, too many things to account for with my plans. Makes it necessary to step back and determine what's truly important, what truly necessitates my attention. Some things have to be discarded in order to clear a path to your goals. @@ -419,6 +419,18 @@ return { I guess, after all this, I've come to realize that eventually you just have to accept that things won't get done if... well, if you don't do them. And that's okay. Not every project has to finished, not every dream seen through. ]], + ['rEX eNH eMS eGV rVL eDH eIN rAS eDP'] = STRING.trimIndent [[ + The Underwhelmed Smithy... Is this even truly a "Smithy" if it doesn't have eEX eVL eAS? + Well, I found it funny, and it is an interesting run in my opinion, so here ya go. + The only reason this has dev commentary is because of the red text. + ]], + ['uEX eNH eMS eGV uVL eDH eIN uAS eDP'] = STRING.trimIndent [[ + The Whelmed Smithy... Is this even truly a "Smithy" if it doesn't have eEX eVL eAS? + Now, I used to think that you could be overwhelmed or underwhelmed, but you could never just be + w h e l m e d + Turns out that "officially" whelmed is just a synonym of overwhelmed, although in more contemporary examples it has taken on a + definition of "content" or "satisfied." Which definition is more accurate for this, I am not sure. I leave that up to you, player. + ]], --one of mine ['eEX uGV eDH eAS'] = STRING.trimIndent [[ But It Isn't One Of Mine, the Easy Mode counterpart to the Patience Is A Virtue achievement. diff --git a/data/devscore.lua b/data/devscore.lua index ac926d26..3a9b5a1a 100644 --- a/data/devscore.lua +++ b/data/devscore.lua @@ -1,4 +1,4 @@ -local d = {ASMSrDHrIN=848.9,swamp_water_lite_plus=4878.84,swamp_water_plus=2714.92,talentless=7817.15,quest_rationing=631.02,the_responsible_one=18,the_unreliable_one=14,the_responsible_one_plus=144,guardian_angel=6061.19,carried=5528.27,level_19_cap=7207.94,the_escape_artist=132,the_artist_trinity=503.8,fel_magic=107,empurple=2919.81,autoplay_is_awesome=1658.4,spotless=2916.6,a_mutual_agreement=3620.9,the_cheaters=1786.5,overprotection=1986.85,clutch_main=191,sunk_cost=4278.1,wax_wings=2412.74,the_masterful_juggler=122,the_oblivious_artist=172,zero_to_sixty=5.4,speed_bonus=10,under_the_radar=119.726,arrogance=772.74,scarcity_mindset=57,detail_oriented=0,psychokinesis=1692,divine_rejection=1649.9,moon_struck=0,lovers_promise=10598.95,hardcore_beginning=13.88,love_hotel=2.597011165,financially_responsible=5.898309714,unfair_battle=4.344901018,museum_heist=2.4841288230001,workaholic=2.3799148589999,human_experiment=2.733007991,thermal_anomaly=0.467,ultra_dash=0.496,identity=0,the_perfectionist=8310.52,cruise_control=23,dazed=16,drag_racing=29,space_race=209,fickle_fuel=851.3,the_spike_of_all_time_plus=498,blight=7733.35,desolation=6284.45,havoc=3656.14,pandemonium=3481.3,inferno=2875.1,purgatory=1840,perdition=1624.7,cataclysm=1395.49,annihilation=777.19,armageddon=423.31,abyss=196.02,cut_off=0,worn_out=0,the_harbinger=0,final_defiance=0,speedrun_speedrunning=0,abyss_weaver=0,royal_resistance=0,lovers_stand=0,romantic_homicide=0,benevolent_ambition=0,blazing_speed=0,dusty_memories=0,its_kinda_rare=0,fruitless_effort=0,false_god=0,respectful=0,zenith_relocation=0,intended_glitch=0,lucky_coincidence=0,zenith_traveler=0,dark_force=0,return_to_the_light=true,smooth_dismount=0,naga_eyes=26.456631063,clicker_speedrun=15.466656532,zenith_explorer_plus=18681.62,zenith_explorer=10666.27,plonk=148.99,speed_player=6735,rMS=3982.7,rNH=6282.1,rVL=6036.9,DH=9644.52,elegance=443220,clicker=1144046,perfect_speedrun=23.747579831,VL=11377.6,NH=10586.4,MS=6326.3,IN=10929.7,GV=10604.39,EX=8612.63,DP=10598.95,contender=10266,AS=18681.62,garbage_offensive=2239880,tower_climber=6651015.7,tower_regular=31857,rIN=5503.13,rGV=8520,rEX=2807.73,rDP=3980.74,rDH=4273.85,rAS=13294.7,supercharged=288,supercharged_plus=447,multitasker=61866.8,effective=41446.887071386,zenith_speedrun=48.891,zenith_speedrun_plus=28.87,zenith_challenger=97361.9,divine_challenger=54681.7,zenith_speedrunner=480.712,divine_speedrunner=691.846,the_spike_of_all_time=437,the_spike_of_all_time_minus=192,clock_out=874,vip_list=126,GVIN=9358.41,ASNH=14508.3,DPEX=5417.82,GVNH=8373.29,DHMSNH=7020.5,DHEXNH=6784.1,DHEXMSVL=2766.57,ASEXVL=4432.7,swamp_water_lite=4878.84,swamp_water=2985.03,rGVrIN=6076.5,EXNHrAS=5891.7,INrASrDHrNH=2711.9,DHEXrGV=6096.52,EXGVNHrMS=2860.57,ASDPGVrMSrNH=2005.6,DHrEXrVL=1664.66,ASGVrDPrMS=1853.87,NHVLrDPrGV=2178.42,VLrEXrIN=1688.17,rDPrEX=2279.1,INMSrDHrEX=1244.64, +local d = {DHrEXrVL=1664.66,ASGVrDPrMS=1853.87,NHVLrDPrGV=2178.42,VL=11377.6,NH=10586.4,MS=6326.3,IN=10929.7,GV=10604.39,EX=8612.63,DP=10598.95,DH=9644.52,AS=18681.62,rVL=6036.9,rNH=6282.1,rMS=3982.7,rIN=5503.13,rGV=8520,rEX=2807.73,rDP=3980.74,rDH=4273.85,rAS=13294.7,royal_resistance=0,lovers_stand=0,romantic_homicide=0,benevolent_ambition=0,blazing_speed=0,dusty_memories=0,its_kinda_rare=0,fruitless_effort=0,false_god=0,respectful=0,zenith_relocation=0,intended_glitch=0,lucky_coincidence=0,zenith_traveler=0,dark_force=0,return_to_the_light=true,smooth_dismount=0,moon_struck=0,lovers_promise=10598.95,hardcore_beginning=13.88,love_hotel=2.597011165,financially_responsible=5.898309714,unfair_battle=4.344901018,museum_heist=2.4841288230001,workaholic=2.3799148589999,human_experiment=2.733007991,thermal_anomaly=0.467,ultra_dash=0.496,perfect_speedrun=22.744034702,the_perfectionist=8310.52,cruise_control=23,identity=0,ASDPGVrMSrNH=2005.6,speed_bonus=10,zero_to_sixty=5.4,the_oblivious_artist=172,wax_wings=2412.74,sunk_cost=4278.1,autoplay_is_awesome=1658.4,spotless=2916.6,clutch_main=191,the_masterful_juggler=122,empurple=2919.81,level_19_cap=7207.94,the_artist_trinity=503.8,the_escape_artist=132,the_cheaters=1786.5,a_mutual_agreement=3620.9,overprotection=1986.85,abyss_weaver=0,speedrun_speedrunning=0,final_defiance=0,the_harbinger=0,VLrEXrIN=1688.17,rDPrEX=2279.1,INMSrDHrEX=1244.64,clicker=1159046,under_the_radar=54.641,pandemonium=3481.3,inferno=2875.1,purgatory=1840,perdition=1624.7,cataclysm=1395.49,annihilation=777.19,armageddon=423.31,abyss=196.02,cut_off=0,worn_out=0,desolation=6284.45,blight=7733.35,the_spike_of_all_time_plus=626,fickle_fuel=851.3,space_race=209,drag_racing=29,havoc=3656.14,divine_rejection=1649.9,psychokinesis=1692,detail_oriented=0,scarcity_mindset=57,arrogance=772.74,ASMSrDHrIN=848.9,swamp_water_lite_plus=4878.84,swamp_water_plus=2714.92,talentless=7817.15,quest_rationing=631.02,the_responsible_one=18,the_responsible_one_plus=144,the_unreliable_one=14,guardian_angel=6061.19,carried=5528.27,contender=10447,elegance=448861,garbage_offensive=2268623,tower_climber=6726205.5,tower_regular=32310,speed_player=6862,plonk=148.99,zenith_explorer=10666.27,zenith_explorer_plus=18681.62,clicker_speedrun=15.466656532,naga_eyes=26.456631063,supercharged=288,supercharged_plus=447,multitasker=61866.8,effective=41446.887071386,zenith_speedrun=47.469,zenith_speedrun_plus=28.87,zenith_challenger=97361.9,divine_challenger=54681.7,zenith_speedrunner=480.712,divine_speedrunner=691.846,the_spike_of_all_time=533,the_spike_of_all_time_minus=192,clock_out=892,vip_list=130,GVIN=9358.41,ASNH=14508.3,DPEX=5417.82,GVNH=8373.29,DHMSNH=7020.5,DHEXNH=6784.1,DHEXMSVL=2766.57,ASEXVL=4432.7,swamp_water_lite=4878.84,swamp_water=2985.03,rGVrIN=6076.5,EXNHrAS=5891.7,INrASrDHrNH=2711.9,DHEXrGV=6096.52,EXGVNHrMS=2860.57,dazed=16, --deleted MrZ score patience_is_a_virtue=2627.37, -- Trevor Smithy Dev scores diff --git a/data/revive.lua b/data/revive.lua index 4176444f..b48fb8b1 100644 --- a/data/revive.lua +++ b/data/revive.lua @@ -26,9 +26,7 @@ local function notEMSorF6() return math.max(GAME.floor, GAME.negFloor) >= 6 and local function notEasyName() return not STAT.easyName end -- whether or not to use SWAMP WATER or BATH WATER local function easyName() return STAT.easyName end local function EDP() return GAME.mod.DP == -1 and GAME.mod.NH ~= 2 and GAME.animDuration < 26 end --3rd quest, don't do if rNH or excessive animDuration -local function notUASandEDP() return not (GAME.mod.AS == 2 and URM and GAME.mod.DP == -1) end -- friend won't let you kill yourself local function notEDHandEDP() return GAME.mod.DH ~= -1 and GAME.mod.DP ~= -1 end -- friend removes annoying revive task -local function notRGVandEDP() return not (GAME.mod.GV == 2 and GAME.mod.DP == -1) and math.max(GAME.floor, GAME.negFloor) <= 5 end --- no commit for 6 seconds ---@class Prompt ---@field rank number[] @@ -49,8 +47,8 @@ local d = { { rank = { 1, 2 }, prompt = 'flip', target = 50, short = "Flip 50", text = "Flip 50 cards" }, { rank = { 3, 4 }, prompt = 'flip', target = 120, short = "Flip 120", text = "Flip 120 cards" }, { rank = { 5, 6 }, prompt = 'flip', target = 300, short = "Flip 300", text = "Flip 300 cards" }, - { rank = { 1, 2 }, prompt = 'flip_single', target = 10, short = "Flip single 10", text = "Flip a single card\n10 times in a row", cond = notUASandEDP }, - { rank = { 2, 4 }, prompt = 'flip_single', target = 20, short = "Flip single 20", text = "Flip a single card\n20 times in a row", cond = notUASandEDP }, + { rank = { 1, 2 }, prompt = 'flip_single', target = 10, short = "Flip single 10", text = "Flip a single card\n10 times in a row", cond = function() return not (URM and GAME.mod.AS == 2) end }, + { rank = { 2, 4 }, prompt = 'flip_single', target = 20, short = "Flip single 20", text = "Flip a single card\n20 times in a row", cond = function() return not (URM and GAME.mod.AS == 2) end }, { rank = { 1, 2 }, prompt = 'commit', target = 6, short = "Commit 6x", text = "Commit 6 times" }, { rank = { 2, 3 }, prompt = 'commit', target = 15, short = "Commit 15x", text = "Commit 15 times" }, { rank = { 3, 5 }, prompt = 'commit', target = 30, short = "Commit 30x", text = "Commit 30 times" }, @@ -128,7 +126,7 @@ local d = { { rank = { 4, 6 }, prompt = 'keep_health_safe', target = 8, short = "Safe HP 8s", text = "Keep HP safe\nfor 8 seconds", cond = F6 }, { rank = { 4, 5 }, prompt = 'keep_health_danger', target = 3, short = "Critical HP 3s", text = "Keep HP critical\nfor 3 seconds", cond = notEMSorF6 }, { rank = { 2, 5 }, prompt = 'keep_no_mouse', target = 4, short = "No mouse 4s", text = "Don't use the mouse\nfor 4 seconds", cond = f5 }, - { rank = { 2, 4 }, prompt = 'keep_no_commit', target = 6, short = "No commit 6s", text = "Don't commit\nfor 6 seconds", cond = notRGVandEDP }, + { rank = { 2, 4 }, prompt = 'keep_no_commit', target = 6, short = "No commit 6s", text = "Don't commit\nfor 6 seconds", cond = function() return math.max(GAME.floor, GAME.negFloor) <= 5 and not ((URM or GAME.mod.DP == -1) and GAME.mod.GV == 2) end }, { rank = { 3, 6 }, prompt = 'keep_no_cancel', target = 8, short = "No cancel 8s", text = "Don't cancel\nfor 8 seconds" }, { rank = { 2, 5 }, prompt = 'keep_no_keyboard', target = 10, short = "No keyboard 10s", text = "Don't use the keyboard\nfor 10 seconds", cond = F6 }, { rank = { 3, 5 }, prompt = 'keep_no_perfect', target = 12, short = "No perfect 12s", text = "Have no perfect\npasses for 12 seconds", cond = notENH }, diff --git a/data/sfx.lua b/data/sfx.lua index d862fd47..cab5547b 100644 --- a/data/sfx.lua +++ b/data/sfx.lua @@ -97,34 +97,34 @@ return { combo_2 = { 296, 1 }, combo_3 = { 131, 1 }, combo_4 = { 707, 1 }, - combo_5= {435, 1}, - combo_6= {391, 1}, - combo_7= {30, 1}, - combo_8= {752, 1}, - combo_9= {95, 1}, - combo_10= {329, 1}, - combo_11= {772, 1}, - combo_12= {605, 1}, - combo_13= {281, 1}, - combo_14= {159, 1}, - combo_15= {812, 1}, - combo_16= {62, 1}, - combo_1_power= {290, 1}, - combo_2_power= {7, 1}, - combo_3_power= {518, 1}, - combo_4_power= {21, 1}, - combo_5_power= {352, 1}, - combo_6_power= {143, 1}, - combo_7_power= {558, 1}, - combo_8_power= {356, 1}, - combo_9_power= {241, 1}, - combo_10_power= {288, 1}, - combo_11_power= {354, 1}, - combo_12_power= {109, 1}, - combo_13_power= {197, 1}, - combo_14_power= {395, 1}, - combo_15_power= {206, 1}, - combo_16_power= {788, 2}, + combo_5 = { 435, 1 }, + combo_6 = { 391, 1 }, + combo_7 = { 30, 1 }, + combo_8 = { 752, 1 }, + combo_9 = { 95, 1 }, + combo_10 = { 329, 1 }, + combo_11 = { 772, 1 }, + combo_12 = { 605, 1 }, + combo_13 = { 281, 1 }, + combo_14 = { 159, 1 }, + combo_15 = { 812, 1 }, + combo_16 = { 62, 1 }, + combo_1_power = { 290, 1 }, + combo_2_power = { 7, 1 }, + combo_3_power = { 518, 1 }, + combo_4_power = { 21, 1 }, + combo_5_power = { 352, 1 }, + combo_6_power = { 143, 1 }, + combo_7_power = { 558, 1 }, + combo_8_power = { 356, 1 }, + combo_9_power = { 241, 1 }, + combo_10_power = { 288, 1 }, + combo_11_power = { 354, 1 }, + combo_12_power = { 109, 1 }, + combo_13_power = { 197, 1 }, + combo_14_power = { 395, 1 }, + combo_15_power = { 206, 1 }, + combo_16_power = { 788, 2 }, combobreak = { 377, 1 }, -- btb_1= {507, 1}, @@ -174,7 +174,7 @@ return { -- finish= {409, 2.7}, -- death= {798, 0.6}, elim = { 460, 0.5 }, - -- levelup= {522, 1.4}, + levelup= {522, 1.4}, shatter = { 300, 3 }, hyperalert = { 333, 1.7 }, topout = { 709, 4.6 }, @@ -239,7 +239,7 @@ return { -- level500= {587, 5}, maintenance = { 178, 1.1 }, map_change = { 538, 2.12 }, - -- matchintro= {489, 16.5}, + matchintro= {489, 16.5}, -- mission_free= {88, 3.4}, -- mission_league= {672, 11.2}, -- mission_versus= {397, 4.9}, diff --git a/main.lua b/main.lua index 3d4752ab..6eb8b476 100644 --- a/main.lua +++ b/main.lua @@ -12,8 +12,7 @@ STRING.install() SCR.setSize(1600, 1000) -for _, v in next, { - 'customAssets', +FILE.createDirectory({ 'customAssets/achievements', 'customAssets/badges', 'customAssets/card', @@ -24,7 +23,7 @@ for _, v in next, { 'customAssets/revive', 'customAssets/stat', 'customAssets/tower', -} do love.filesystem.createDirectory(v) end +}) ---@return any love.Texture @@ -165,6 +164,7 @@ TEXTURE = { towerBG = { assets 'tower/f1.jpg', assets 'tower/f2.jpg', assets 'tower/f3.jpg', assets 'tower/f4.jpg', assets 'tower/f5.jpg', assets 'tower/f6.jpg', assets 'tower/f7.jpg', assets 'tower/f8.jpg', assets 'tower/f9.jpg', assets 'tower/f10.png' }, moon = assets 'tower/moon.png', stars = assets 'tower/stars.png', + warning = assets 'finalwarning.png', revive = { norm = assets 'revive/norm.png', @@ -679,8 +679,9 @@ TEXTS = { -- Font size can only be 30 and 50 here !!! zpChange = GC.newText(FONT.get(30)), dcBest = GC.newText(FONT.get(30)), dcTimer = GC.newText(FONT.get(30)), + srTimer = GC.newText(FONT.get(30)), title = GC.newText(FONT.get(50), "EXPERT QUICK PICK"), - load = GC.newText(FONT.get(50), "JOINING ROOM..."), + load = GC.newText(FONT.get(50)), pb = GC.newText(FONT.get(50)), endResult = GC.newText(FONT.get(30)), endHeight = GC.newText(FONT.get(50)), @@ -781,86 +782,105 @@ Metatable = { best_highscore = { __index = function() return 0 end }, best_speedrun = { __index = function() return 1e99 end }, } -BEST = { - highScore = setmetatable({}, Metatable.best_highscore), - speedrun = setmetatable({}, Metatable.best_speedrun), -} -STAT = { - mod = 'easyMode', - version = nil, -- will be set after loading - system = SYSTEM, - joinDate = os.date("%b %Y"), - hid = os.date("%d%S%m%M%y%H") .. math.random(26000, 42000) .. math.random(42000, 62000), - uid = "ANON-" .. os.date("%d_") .. math.random(2600, 6200), - keybind = { - "q", "w", "e", "r", "t", "y", "u", "i", "o", - "a", "s", "d", "f", "g", "h", "j", "k", "l", - "space", "z", "x", "c" - }, - aboutme = "Click the Zenith!", - maxFloor = 1, - maxHeight = 0, - heightDate = "NO DATE", - minTime = 2600, - timeDate = "NO DATE", - - zp = 0, - dzp = 0, - peakZP = 0, - peakDZP = 0, - dailyBest = 0, - dailyMastered = false, - lastDay = 0, - vipListCount = 0, - clockOutCount = 0, - clicker = false, - - totalGame = 0, - totalTime = 0, - totalQuest = 0, - totalPerfect = 0, - totalHeight = 0, - totalBonus = 0, - totalFloor = 0, - totalFlip = 0, - totalAttack = 0, - totalGiga = 0, - totalF10 = 0, - badge = {}, - - fullscreen = true, - syscursor = false, - cardBrightness = 90, - bgBrightness = 40, - bg = true, - sfx = 60, - bgm = 100, - - autoMute = false, - oldHitbox = false, - easyName = false, - imperial = false, - promotion = true, - stacker = false, - rold = false, - oldTransparentCard = false, - unlockAll = false, - easyModeClicker = false, - greenClicker = false, -} +-- Create BEST, STAT, ACHV tables, only used when launching and on resetall +function INIT_DATA() + BEST = { + highScore = setmetatable({}, Metatable.best_highscore), + speedrun = setmetatable({}, Metatable.best_speedrun), + } + + STAT = { + mod = 'easyMode', + version = nil, -- will be set after loading + system = SYSTEM, + modTime = os.time(), + srTimer_life = 0, + srTimer_game = 0, + joinDate = os.date("%b %Y"), + hid = os.date("%d%S%m%M%y%H") .. math.random(26000, 42000) .. math.random(42000, 62000), + uid = "ANON-" .. os.date("%d_") .. math.random(2600, 6200), + keybind = { + "q", "w", "e", "r", "t", "y", "u", "i", "o", + "a", "s", "d", "f", "g", "h", "j", "k", "l", + "space", "z", "x", "c" + }, + aboutme = "Click the Zenith!", + maxFloor = 1, + maxHeight = 0, + heightDate = "NO DATE", + minTime = 2600, + timeDate = "NO DATE", + + zp = 0, + dzp = 0, + peakZP = 0, + peakDZP = 0, + dailyBest = 0, + dailyMastered = false, + lastDay = 0, + vipListCount = 0, + clockOutCount = 0, + clicker = false, + + totalGame = 0, + totalTime = 0, + totalQuest = 0, + totalPerfect = 0, + totalHeight = 0, + totalBonus = 0, + totalFloor = 0, + totalFlip = 0, + totalAttack = 0, + totalGiga = 0, + totalF10 = 0, + badge = {}, + + fullscreen = true, + syscursor = false, + cardBrightness = 90, + bgBrightness = 40, + bg = true, + sfx = 60, + bgm = 100, + + autoMute = false, + oldHitbox = false, + easyName = false, + imperial = false, + promotion = true, + stacker = false, + rold = false, + oldTransparentCard = false, + unlockAll = false, + easyModeClicker = false, + greenClicker = false, + } -ACHV = {} + ACHV = {} -AchvNotice = {} + AchvNotice = {} +end + +INIT_DATA() TestMode = false -function SaveBest() if not (TestMode or GAME.multiplePiecesActive) then love.filesystem.write('best.luaon', 'return' .. TABLE.dumpDeflate(BEST)) end end +function SaveBest() + if (TestMode or GAME.multiplePiecesActive) then return end + love.filesystem.write('best.luaon', 'return' .. TABLE.dumpDeflate(BEST)) +end -function SaveStat() if not (TestMode or GAME.multiplePiecesActive) then love.filesystem.write('stat.luaon', 'return' .. TABLE.dumpDeflate(STAT)) end end +function SaveStat() + if (TestMode or GAME.multiplePiecesActive) then return end + STAT.modTime = os.time() + love.filesystem.write('stat.luaon', 'return' .. TABLE.dumpDeflate(STAT)) +end -function SaveAchv() if not (TestMode or GAME.multiplePiecesActive) then love.filesystem.write('achv.luaon', 'return' .. TABLE.dumpDeflate(ACHV)) end end +function SaveAchv() + if (TestMode or GAME.multiplePiecesActive) then return end + love.filesystem.write('achv.luaon', 'return' .. TABLE.dumpDeflate(ACHV)) +end local msgTime = 0 local bufferedMsg = {} @@ -1050,7 +1070,6 @@ SCN.add('achv', require 'scene/achv') SCN.add('conf', require 'scene/conf') SCN.add('about', require 'scene/about') SCN.add('ending', require 'scene/ending') -SCN.add('zcem', require 'scene/zcem') ZENITHA.setFirstScene('joining') local gc = love.graphics @@ -1143,6 +1162,7 @@ BgmData = { } BgmPlaying = false ---@type ZC.bgmName | false +SongNamePlaying = false -- Same as BgmPlaying, but this distinguishes f0(r) and f1(r) for album page BgmLooping = false BgmNeedSkip = false BgmNeedStop = false @@ -1159,34 +1179,41 @@ end function PlayBGM(name, force) if GAME.teramusic and not force then return end + SongNamePlaying = name local last = BgmPlaying if GAME.playing and (RevMusicMode() or GAME.forceRev) then name = name .. 'r' end if name == 'fomgr' then name = 'fomg' end - if name:sub(1, 2) == 'f0' then + if name == 'f0r' then BgmPlaying = 'f0' - elseif name:sub(1, 2) == 'f1' and name:sub(1, 3) ~= 'f10' then + elseif name == 'f1r' then -- Note: 'f1ex' is only a track name, not musicID BgmPlaying = 'f1' else BgmPlaying = name end if not BgmData[BgmPlaying] then return end - BgmLooping = BgmData[BgmPlaying].loop - BgmNeedSkip = BgmData[BgmPlaying].teleport + BgmNeedStop = false if BgmPlaying == 'f0' then BgmLooping = false + BgmNeedSkip = BgmData[BgmPlaying].teleport + BGM.play(BgmSet.f0) RefreshBGM(name) elseif BgmPlaying == 'f1' then + BgmLooping = BgmData[BgmPlaying].loop + BgmNeedSkip = BgmData[BgmPlaying].teleport + BGM.play(BgmSet.f1, force and '' or '-sdin') local start = math.random(3, 5) * BgmData.f1.introLen BgmNeedSkip[1] = start + BgmData.f1.introLen BGM.set('all', 'seek', start) RefreshBGM(name) - elseif name == 'tera' or name == 'terae' or name == 'teral' or name == 'terael'then + elseif name == 'tera' or name == 'terae' or name == 'teral' or name == 'terael' then + BgmLooping = BgmData[BgmPlaying].loop + BgmNeedSkip = BgmData[BgmPlaying].teleport BGM.play(name, '-sdin') local startFrom if last then @@ -1198,10 +1225,10 @@ function PlayBGM(name, force) BgmNeedSkip[1] = start + BgmData.tera.introLen BGM.set('all', 'seek', start) RefreshBGM() - else - if BGM.play(name, force and '' or '-sdin') then - RefreshBGM() - end + elseif BGM.play(name, force and '' or '-sdin') then + BgmLooping = BgmData[BgmPlaying].loop + BgmNeedSkip = BgmData[BgmPlaying].teleport + RefreshBGM() end end @@ -1435,7 +1462,6 @@ function ReloadTexts() for _, W in next, SCN.scenes.conf.widgetList do W:reset() end for _, W in next, SCN.scenes.about.widgetList do W:reset() end for _, W in next, SCN.scenes.records.widgetList do W:reset() end - for _, W in next, SCN.scenes.zcem.widgetList do W:reset() end AchvText:setFont(FONT.get(30)) AboutText:setFont(FONT.get(70)) DevNoteText:setFont(FONT.get(30)) @@ -1625,6 +1651,8 @@ function ZENITHA.globalEvent.keyDown(key, isRep) end end +function ZENITHA.globalEvent.quit() SaveStat() end + do -- Auto mute when unfocused local function task_autoSoundOff() coroutine.yield() @@ -1816,7 +1844,7 @@ function Daemon_Slow() local length while true do -- Music syncing - if BgmPlaying == 'f0' and BGM.isPlaying() then + if BgmPlaying == 'f0' and BGM.isPlaying() and not MOBILE then length = length or lib[f0List[1]].source:getDuration() local t0 = lib[f0List[1]].source:tell() % length for i = #f0List, 2, -1 do @@ -1838,7 +1866,21 @@ function Daemon_Slow() end -- HTTP returns - local msg = ASYNC.get('submitDaily') + --[[local msg = ASYNC.get('checkUpdate') + if msg then + local suc, res = pcall(JSON.decode, msg) + if suc and res and res.tag_name then + if (require 'version'.appVer):lower() == res.tag_name then + LOG('info', "Already on latest version (" .. res.tag_name .. ")") + else + SFX.play('social_notify_major') + MSG('info', "New version " .. res.tag_name .. " available!", 6.26) + end + else + LOG('info', "Failed to check for updates") + end + end]] + msg = ASYNC.get('submitDaily') if msg then local suc, res = pcall(JSON.decode, msg) local duration = GAME.playing and 0 or 10 @@ -1930,6 +1972,11 @@ function Daemon_Fast() local dt = yield() + -- Speedrun timer + if STAT.srTimer_life then + STAT.srTimer_life = STAT.srTimer_life + dt + end + -- Mouse holding animation if not STAT.syscursor then pressValue = msIsDown(1, 2) and 1 or expApproach(pressValue, 0, dt * 12) diff --git a/module/card.lua b/module/card.lua index 9592cb50..c626efb5 100644 --- a/module/card.lua +++ b/module/card.lua @@ -291,9 +291,11 @@ function Card:setActive(auto, key) revOn = false noSpin = true self.active = false - self:shake() - SFX.play('no') - MSG('dark', "Reach F10 with this mod first!") + if STAT.maxFloor >= 10 then + self:shake() + SFX.play('no') + MSG('dark', "Reach F10 with this mod first!") + end return end local wasRev = M[self.id] == 2 diff --git a/module/game.lua b/module/game.lua index 602850ee..c36d7b27 100644 --- a/module/game.lua +++ b/module/game.lua @@ -125,7 +125,6 @@ local ins, rem = table.insert, table.remove ---@field OSPActivated boolean ---@field finalFatigueOSPActivated boolean ---@field bonusRecoveryHealth number ----@field teraComplete boolean ---@field teraStartHeight number ---@field teraLostHeight number ---@field customUltraCombo boolean @@ -171,7 +170,7 @@ local GAME = { bgLastH = 0, lifeShow = 0, lifeShow2 = 0, - prevPB = -260, + prevPB = -2600, modIB = GC.newSpriteBatch(TEXTURE.modIcon), resIB = GC.newSpriteBatch(TEXTURE.modIcon), comboMP = 0, @@ -227,6 +226,7 @@ local GAME = { windupAnim = {}, ---@type Windup[] zenithTraveler = false, + pieceEffectID = 0, nightcore = false, slowmo = false, glassCard = false, @@ -282,6 +282,7 @@ GAME.time = 0 GAME.spikeCounter = 0 GAME.spikeTimer = 0 GAME.floorTime = 0 +GAME.f10Time = love.timer.getTime() GAME.reviveTime = false GAME.floor = 1 GAME.rank = 1 @@ -478,168 +479,34 @@ function GAME.getComboName(list, mode) end end - -- https://www.nationalchurchillmuseum.org/never-give-in-never-never-never.html#:~:text=You%20cannot%20tell,of%20the%20enemy. local colorModNumber = 1 - local messyText = "" + local eINeMSAS = M.IN == -1 and M.MS == -1 and M.AS ~= 0 and not STAT.easyName + local modCodes = {'EX', 'NH', 'MS', 'GV', 'VL', 'DH', 'IN', 'AS', 'DP'} for i = 1, len - 1 do - if M.IN == -1 and M.MS == -1 and M.AS ~= 0 and not STAT.easyName then - --psuedocode: goal - get card order from CD[j].initOrder, use that to generate a new index for the MD.textColor - -- forgive me lord for i have sinned - if MD.name[list[i]] == 'expert' then - --MSG('dark', "Current Card: " .. CD[1].initOrder) - colorModNumber = CD[1].initOrder - elseif MD.name[list[i]] == 'nohold' then - --MSG('dark', "Current Card: " .. CD[2].initOrder) - colorModNumber = CD[2].initOrder - elseif MD.name[list[i]] == 'messy' then - --MSG('dark', "Current Card: " .. CD[3].initOrder) - colorModNumber = CD[3].initOrder - elseif MD.name[list[i]] == 'gravity' then - --MSG('dark', "Current Card: " .. CD[4].initOrder) - colorModNumber = CD[4].initOrder - elseif MD.name[list[i]] == 'volatile' then - --MSG('dark', "Current Card: " .. CD[5].initOrder) - colorModNumber = CD[5].initOrder - elseif MD.name[list[i]] == 'doublehole' then - --MSG('dark', "Current Card: " .. CD[6].initOrder) - colorModNumber = CD[6].initOrder - elseif MD.name[list[i]] == 'invisible' then - --MSG('dark', "Current Card: " .. CD[7].initOrder) - colorModNumber = CD[7].initOrder - elseif MD.name[list[i]] == 'allspin' then - --MSG('dark', "Current Card: " .. CD[8].initOrder) - colorModNumber = CD[8].initOrder - elseif MD.name[list[i]] == 'duo' then - --MSG('dark', "Current Card: " .. CD[9].initOrder) - colorModNumber = CD[9].initOrder - end - if colorModNumber == 1 then - ins(fstr, MD.textColor['EX']) - messyText = "e" - elseif colorModNumber == 2 then - ins(fstr, MD.textColor['NH']) - messyText = "h" - elseif colorModNumber == 3 then - ins(fstr, MD.textColor['MS']) - messyText = "m" - elseif colorModNumber == 4 then - ins(fstr, MD.textColor['GV']) - messyText = "g" - elseif colorModNumber == 5 then - ins(fstr, MD.textColor['VL']) - messyText = "v" - elseif colorModNumber == 6 then - ins(fstr, MD.textColor['DH']) - messyText = "d" - elseif colorModNumber == 7 then - ins(fstr, MD.textColor['IN']) - messyText = "i" - elseif colorModNumber == 8 then - ins(fstr, MD.textColor['AS']) - messyText = "a" - elseif colorModNumber == 9 then - ins(fstr, MD.textColor['DP']) - messyText = "o" - end - --ins(fstr, {COLOR.HEX "C29F68FF"}) - if STAT.easyName then - ins(fstr, MD.adj[easyList[i]] .. " ") - else - ins(fstr, MD.adj[list[i]] .. " ") + if eINeMSAS then + for j = 1, #modCodes do + if MD.name[list[i]] == MD.name[modCodes[j]] then + colorModNumber = CD[j].initOrder + end end - --ins(fstr, messyText .. MD.adj[list[i]] .. " ") - --MSG('dark', "Added mod to quest: " .. MD.name[list[i]]) + ins(fstr, MD.textColor[modCodes[colorModNumber]]) else - if STAT.easyName then - ins(fstr, MD.textColor[easyList[i]]) - else - ins(fstr, MD.textColor[list[i]]) - end - if STAT.easyName then - ins(fstr, MD.adj[easyList[i]] .. " ") - else - ins(fstr, MD.adj[list[i]] .. " ") - end + ins(fstr, MD.textColor[STAT.easyName and easyList[i] or list[i]]) end + ins(fstr, MD.adj[STAT.easyName and easyList[i] or list[i]] .. " ") end - if M.IN == -1 and M.MS == -1 and M.AS ~= 0 and not STAT.easyName then - --ins(fstr, {COLOR.HEX "C29F68FF"}) - -- forgive me lord for i have sinned yet again - if MD.name[list[len]] == 'expert' then - --MSG('dark', "Current Card: " .. CD[1].initOrder) - colorModNumber = CD[1].initOrder - elseif MD.name[list[len]] == 'nohold' then - --MSG('dark', "Current Card: " .. CD[2].initOrder) - colorModNumber = CD[2].initOrder - elseif MD.name[list[len]] == 'messy' then - --MSG('dark', "Current Card: " .. CD[3].initOrder) - colorModNumber = CD[3].initOrder - elseif MD.name[list[len]] == 'gravity' then - --MSG('dark', "Current Card: " .. CD[4].initOrder) - colorModNumber = CD[4].initOrder - elseif MD.name[list[len]] == 'volatile' then - --MSG('dark', "Current Card: " .. CD[5].initOrder) - colorModNumber = CD[5].initOrder - elseif MD.name[list[len]] == 'doublehole' then - --MSG('dark', "Current Card: " .. CD[6].initOrder) - colorModNumber = CD[6].initOrder - elseif MD.name[list[len]] == 'invisible' then - --MSG('dark', "Current Card: " .. CD[7].initOrder) - colorModNumber = CD[7].initOrder - elseif MD.name[list[len]] == 'allspin' then - --MSG('dark', "Current Card: " .. CD[8].initOrder) - colorModNumber = CD[8].initOrder - elseif MD.name[list[len]] == 'duo' then - --MSG('dark', "Current Card: " .. CD[9].initOrder) - colorModNumber = CD[9].initOrder - end - if colorModNumber == 1 then - ins(fstr, MD.textColor['EX']) - messyText = "e" - elseif colorModNumber == 2 then - ins(fstr, MD.textColor['NH']) - messyText = "h" - elseif colorModNumber == 3 then - ins(fstr, MD.textColor['MS']) - messyText = "m" - elseif colorModNumber == 4 then - ins(fstr, MD.textColor['GV']) - messyText = "g" - elseif colorModNumber == 5 then - ins(fstr, MD.textColor['VL']) - messyText = "v" - elseif colorModNumber == 6 then - ins(fstr, MD.textColor['DH']) - messyText = "d" - elseif colorModNumber == 7 then - ins(fstr, MD.textColor['IN']) - messyText = "i" - elseif colorModNumber == 8 then - ins(fstr, MD.textColor['AS']) - messyText = "a" - elseif colorModNumber == 9 then - ins(fstr, MD.textColor['DP']) - messyText = "o" - end - if STAT.easyName then - ins(fstr, MD.noun[easyList[len]]) - else - ins(fstr, MD.noun[list[len]]) + if eINeMSAS then + for j = 1, #modCodes do + if MD.name[list[len]] == MD.name[modCodes[j]] then + colorModNumber = CD[j].initOrder + end end - --ins(fstr, messyText .. MD.noun[list[len]]) - --MSG('dark', "Added mod to quest: " .. MD.name[list[len]]) + ins(fstr, MD.textColor[modCodes[colorModNumber]]) else - if STAT.easyName then - ins(fstr, MD.textColor[easyList[len]]) - else - ins(fstr, MD.textColor[list[len]]) - end - if STAT.easyName then - ins(fstr, MD.noun[easyList[len]]) - else - ins(fstr, MD.noun[list[len]]) - end + ins(fstr, MD.textColor[STAT.easyName and easyList[len] or list[len]]) end + ins(fstr, MD.noun[STAT.easyName and easyList[len] or list[len]]) + if M.IN > 0 then local r = rnd(0, 3) for i = 1, #fstr, 2 do @@ -763,8 +630,6 @@ function GAME.anim_setMenuHide(t) w.conf:resetPos() w.about.x = cLerp(-60, 90, t * 1.5) w.about:resetPos() - w.zcem.x = cLerp(-60, 90, t * 1.5) - w.zcem:resetPos() MSG.setSafeY(75 * (1 - GAME.uiHide)) end @@ -1289,7 +1154,8 @@ function GAME.addXP(xp, falseCommit) GAME.refreshRPC() end if GAME.gigaspeed and not GAME.teramusic and GAME.rank >= TeraMusicReq[GAME.floor] then - if (M.EX == -1 and M.VL == -1 and M.AS == -1 and (M.NH == 0 and M.MS == 0 and M.GV == 0 and M.DH == 0 and M.IN == 0 and M.DP == 0)) then GAME.smithyMode = true end + if GAME.comboStr == 'eASeEXeVL' then GAME.smithyMode = true end + GAME.teraLostHeight = 0 GAME.startTeraAnim() GAME.refreshRPC() end @@ -1390,9 +1256,6 @@ end function GAME.stopTeraspeed(mode) GAME.teramusic = false - if mode == 'f10' then - GAME.teraComplete = true - end if mode == 'drop' then PlayBGM('f' .. max(GAME.floor, GAME.negFloor), true) GAME.teraLostHeight = GAME.roundHeight @@ -1562,6 +1425,7 @@ function GAME.upFloor() -- End game if GAME.floor >= 10 then + GAME.f10Time = love.timer.getTime() if GAME.gigaspeed and #GAME.getHand(true) == 0 and GAME.pieceCount() == 0 and GAME.totalQuest <= 7 then IssueAchv('hyperplonk') end if GAME.gigaspeed or GAME.smithyMode then if GAME.time < STAT.minTime then @@ -1575,40 +1439,13 @@ function GAME.upFloor() IssueAchv('blazing_speed') GAME.finishTera = true end - if GAME.petaspeed then - IssueAchv('peta') - SCN.scenes.achv.unload() - SCN.scenes.achv.load() - end - if GAME.exaspeed then - IssueAchv('exa') - SCN.scenes.achv.unload() - SCN.scenes.achv.load() - end - if GAME.zettaspeed then - IssueAchv('zetta') - SCN.scenes.achv.unload() - SCN.scenes.achv.load() - end - if GAME.yottaspeed then - IssueAchv('yotta') - SCN.scenes.achv.unload() - SCN.scenes.achv.load() - end - if GAME.ronnaspeed then - IssueAchv('ronna') - SCN.scenes.achv.unload() - SCN.scenes.achv.load() - end - if GAME.quettaspeed then - IssueAchv('quetta') - SCN.scenes.achv.unload() - SCN.scenes.achv.load() - end - if not GAME.smithyMode then - -- don't stop my cover until we get to fomg - GAME.stopTeraspeed('f10') - end + if GAME.petaspeed then IssueAchv('peta') end + if GAME.exaspeed then IssueAchv('exa') end + if GAME.zettaspeed then IssueAchv('zetta') end + if GAME.yottaspeed then IssueAchv('yotta') end + if GAME.ronnaspeed then IssueAchv('ronna') end + if GAME.quettaspeed then IssueAchv('quetta') end + if not GAME.smithyMode then GAME.stopTeraspeed('f10') end -- don't stop my cover until we get to fomg local setStr = ((GAME.anyUltra or (URM and M.EX == -1 and GAME.comboStr:count('r') == 0)) and 'u' or '') .. GAME.comboStr local t = BEST.speedrun[setStr] @@ -1951,7 +1788,7 @@ end ---@author: Trevor Smithy function GAME.anim_uneasyModIcon() -- called on game start if requirements met - local p = PieceSFXID + local p = GAME.pieceEffectID GAME.modIB:clear() local hand = GAME.getHand(true) table.sort(hand, modIconSorter) @@ -1977,19 +1814,19 @@ end -------------------------------------------------------------- function GAME.refreshCurrentCombo() - GAME.forceRev = false local hand = GAME.getHand(not GAME.playing) local comboName = GAME.getComboName(hand, 'button') - if not GAME.playing and (M.EX == -1 and M.VL == -1 and M.AS == -1 and (M.NH == 0 and M.MS == 0 and M.GV == 0 and M.DH == 0 and M.IN == 0 and M.DP == 0)) then GAME.smithyMode = true else - if not GAME.playing then GAME.smithyMode = false end - end - local uneasyMode = (M.EX == -1 and URM and M.NH < 2 and M.MS < 2 and M.GV < 2 and M.VL < 2 and M.DH < 2 and M.IN < 2 and M.AS < 2 and M.DP < 2) + local uneasyMode = (M.EX == -1 and URM and not GAME.anyRev) + if not GAME.playing then GAME.smithyMode = (table.concat(TABLE.sort(hand)) == 'eASeEXeVL') end + GAME.forceRev = false GAME.peasantRevolution = false -- SECRET COMBOS if comboName == "EASY BELIEVED DECEPTIVE TRANQUIL ASCENDANT DAMNED COLLAPSED PIERCING SPIN" then comboName = '"THE OVERWHELMED SMITHY"' elseif comboName == "EASY INVISIBLE MESSY TRANQUIL HOLDLESS DOUBLE HOLE GRAVITY SPUN DUO" then comboName = '"THE SWAMPED SMITHY"' + elseif comboName == "VISIBLE TIDY DESPERATE MODERATE SAVED OMNI-SPIN LIFTED FRIENDLY TYRANNY" then + comboName = '"THE UNDERWHELMED SMITHY"' end if not GAME.playing and GAME.anyUltra and #hand > 0 then -- SPECIAL - Trevor Smithy @@ -2017,6 +1854,8 @@ function GAME.refreshCurrentCombo() end elseif comboName == '"THE OVERWHELMED SMITHY"' then comboName = '"THE PARALYZED SMITHY"' + elseif comboName == '"THE UNDERWHELMED SMITHY"' then + comboName = '"THE WHELMED SMITHY"' elseif GAME.badTime and not GAME.badTimeStarted then SCN.scenes.tower.widgetList.reset:setVisible(false) SCN.scenes.tower.widgetList.help:setVisible(false) @@ -2704,7 +2543,7 @@ function GAME.commit(auto, falseCommit) totalAssistPenalty = totalAssistPenalty + CD[i].assistPenalty end end - --MSG("bright", "totalAssistPenalty=".. totalAssistPenalty) + if not falseCommit then if GAME.currentTask then GAME.incrementPrompt('pass') @@ -3278,7 +3117,6 @@ function GAME.start() end if URM and M.VL == 2 and not UltraVlCheck('start') then return end TASK.removeTask_code(Task_MusicEnd) - MusicPlayer = false GAME.omega = false GAME.negFloor = 1 @@ -3290,7 +3128,6 @@ function GAME.start() GAME.smithyMode = false GAME.OSPActivated = false GAME.finalFatigueOSPActivated = false - GAME.teraComplete = false GAME.teraLostHeight = 0 GAME.achv_bestFriendQuest = 0 GAME.achv_shamelessCashgrabQuest = 0 @@ -3323,7 +3160,7 @@ function GAME.start() local attackMulMod = 1 if GAME.eglassCard then attackMulMod = 0.5 end - GAME.attackMul = (GAME.isUltraRun and .62 or (M.EX == -1 and URM and M.NH < 2 and M.MS < 2 and M.GV < 2 and M.VL < 2 and M.DH < 2 and M.IN < 2 and M.AS < 2 and M.DP < 2) and 0.33 or 1) * attackMulMod + GAME.attackMul = (GAME.isUltraRun and .62 or (M.EX == -1 and URM and not GAME.anyRev) and 0.33 or 1) * attackMulMod -- Trevor Smithy GAME.bonusRecoveryHealth = 0 local slowMo = GAME.eslowmo and 0.5 or 0 @@ -3521,7 +3358,18 @@ function GAME.start() if M.DP ~= 0 then IssueAchv('intended_glitch') end end ----@param reason 'forfeit' | 'wrong' | 'time' +function GAME.clearResultStat() + TEXTS.endHeight:set("") + TEXTS.endFloor:set("") + TEXTS.endResult:set("") + TEXTS.zpChange:set("") + TEXTS.floorTime:set("") + TEXTS.rankTime:set("") + TEXTS.easyModeVersion:set("") + GAME.resIB:clear() +end + +---@param reason 'forfeit' | 'wrong' | 'time' | 'reset' function GAME.finish(reason) SCN.scenes.tower.widgetList.help:setVisible(not GAME.zenithTraveler) SCN.scenes.tower.widgetList.help2:setVisible(not GAME.zenithTraveler) @@ -3562,14 +3410,10 @@ function GAME.finish(reason) W:reset() end - if GAME.smithyMode and (GAME.teramusic or GAME.teraLostHeight or GAME.teraComplete) then - local smithyModeHeight = GAME.roundHeight - if GAME.teraLostHeight > 0 then - smithyModeHeight = GAME.teraLostHeight - end - SubmitAchv('programmer_gamer', smithyModeHeight) + if (GAME.teramusic or GAME.teraLostHeight) and GAME.smithyMode then + SubmitAchv('programmer_gamer', GAME.teraLostHeight > 0 and GAME.teraLostHeight or GAME.roundHeight) end - if (GAME.teramusic or GAME.teraLostHeight or GAME.teraComplete) and M.EX == -1 and M.GV == 2 and URM and M.DH == -1 and M.AS == -1 and M.NH == 0 and M.MS == 0 and M.VL == 0 and M.IN == 0 and M.DP == 0 and GAME.enightcore then + if GAME.teramusic and URM and GAME.comboStr == "eASeDHeEXrGV" and GAME.enightcore then SubmitAchv('one_of_mine', GAME.achv_noManualCommitH or GAME.roundHeight) end -- Perfectly Balanced @@ -3658,24 +3502,23 @@ function GAME.finish(reason) GAME.completion[k] = v end end - if unlockRev > 0 or not GAME.anyRev and MATH.roll(.1) and TABLE.countAll(GAME.completion, 2) == 0 then + if (unlockRev > 0 or TABLE.countAll(GAME.completion, 1) > 0 and not GAME.anyRev and MATH.roll(.1)) and TABLE.countAll(GAME.completion, 2) == 0 then local hintText if unlockRev == 0 then hintText = "You've already unlocked REVERSED MOD!\n" else hintText = "You've already unlocked " .. (unlockRev == 1 and "a new REVERSED MOD!\n" or unlockRev .. " new REVERSED MODS!\n") end - hintText = hintText .. ( - MOBILE and - STRING.trimIndent [[ + if MOBILE then + hintText = hintText .. [[ To activate it, press and hold the blue area at the left side, then click on a card that has a star on it. - ]] or - STRING.trimIndent [[ - Activate it by right-clicking on a card that has a star on it. ]] - ) - MSG('dark', hintText, 6.26) + else + hintText = hintText .. "\nActivate it by right-clicking on a card that has a star on it." + end + + MSG('dark', STRING.trimIndent(hintText), 6.26) SFX.play('notify') end if GAME.height >= 12600 then @@ -4126,14 +3969,7 @@ function GAME.finish(reason) end SaveStat() else - TEXTS.endHeight:set("") - TEXTS.endFloor:set("") - TEXTS.endResult:set("") - TEXTS.zpChange:set("") - TEXTS.easyModeVersion:set("") - TEXTS.floorTime:set("") - TEXTS.rankTime:set("") - GAME.resIB:clear() + GAME.clearResultStat() end ReleaseAchvBuffer() @@ -4149,7 +3985,7 @@ function GAME.finish(reason) GAME.prevPB = max(GAME.prevPB, GAME.height) if URM and GAME.height < -10 then - PieceSFXID = 0 + GAME.pieceEffectID = 0 GAME.nightcore = false GAME.slowmo = false GAME.glassCard = false @@ -4300,6 +4136,7 @@ function GAME.update(dt) -- Timers -- Trevor Smithy local timerMulMod = 1 * (GAME.eslowmo and not GAME.badTime and 0.75 or 1) * (GAME.ecloseCard and not GAME.badTime and 2 or 1) + if STAT.srTimer_life then STAT.srTimer_game = STAT.srTimer_game + dt end GAME.time = GAME.time + dt * (GAME.timerMul * timerMulMod) local r = min(GAME.rank, 62) GAME.rankTimer[r] = GAME.rankTimer[r] + dt @@ -4328,8 +4165,9 @@ function GAME.update(dt) local uneasyMode = (M.EX == -1 and URM and M.NH < 2 and M.MS < 2 and M.GV < 2 and M.VL < 2 and M.DH < 2 and M.IN < 2 and M.AS < 2 and M.DP < 2) if ((GAME.slowmo and GAME.time >= 2.6) or (not GAME.slowmo and GAME.time >= 1)) and not GAME.uneasyModIconSelected then if uneasyMode and #GAME.getHand(true) == 2 then - if PieceSFXID == 1 and M.DH == -1 or PieceSFXID == 2 and (M.MS == -1 or M.GV == -1) or PieceSFXID == 3 and M.NH == -1 - or PieceSFXID == 4 and M.AS == -1 or PieceSFXID == 5 and M.DP == -1 or PieceSFXID == 6 and M.IN == -1 or PieceSFXID == 7 and M.VL == -1 then + local p = GAME.pieceEffectID + if p == 1 and M.DH == -1 or p == 2 and (M.MS == -1 or M.GV == -1) or p == 3 and M.NH == -1 + or p == 4 and M.AS == -1 or p == 5 and M.DP == -1 or p == 6 and M.IN == -1 or p == 7 and M.VL == -1 then TASK.new(GAME.anim_uneasyModIcon) end end @@ -4458,16 +4296,13 @@ function GAME.update(dt) if not GAME.DPlock then if M.EX == 2 then + if GAME.eglassCard then + GAME.height = GAME.height + GAME.rank / 4 * (passiveClimbSpeedMod * 0.6) * dt * (GAME.einvisUI and 1 or icLerp(0.5, 3, Floors[GAME.floor].top - GAME.height)) + end if not URM then - GAME.height = GAME.height - dt * (GAME.floor * (GAME.floor + 1) + 10) / 20 - if GAME.eglassCard then - GAME.height = GAME.height + GAME.rank / 4 * passiveClimbSpeedMod*0.6 * dt * (GAME.einvisUI and 1 or icLerp(GAME.eglassCard and 0.5 or 1, GAME.eglassCard and 3 or 6, Floors[GAME.floor].top - GAME.height)) - end + GAME.height = GAME.height - dt * (GAME.floor * (GAME.floor + 1) + 10) / 20 GAME.height = max(GAME.height, Floors[GAME.floor - 1].top) else - if GAME.eglassCard then - GAME.height = GAME.height + GAME.rank / 4 * passiveClimbSpeedMod*0.6 * dt * (GAME.einvisUI and 1 or icLerp(GAME.eglassCard and 0.5 or 1, GAME.eglassCard and 3 or 6, Floors[GAME.floor].top - GAME.height)) - end if GAME.negFloor > 0 then if GAME.negFloor >= 2 then GAME.height = min(GAME.height, NegFloors[GAME.negFloor - 1].bottom) @@ -4480,12 +4315,13 @@ function GAME.update(dt) end if GAME.height < NegFloors[GAME.negFloor].bottom and not GAME.einvisUI then GAME.downFloor() end if GAME.height < NegEvents[GAME.negEvent].h then GAME.nextNegEvent() end - if GAME.height <= -1650 and GAME.badTime and BgmPlaying ~= "fomg" then - PlayBGM('fomg', true) - end - if GAME.height <= -1800 and GAME.badTime and not STAT.greenClicker then - STAT.greenClicker = true - MSG("bright", "YOU DID A THING!") + -- Trevor Smithy (Bad Time) + if GAME.badTime then + if GAME.height <= -1650 and BgmPlaying ~= "f10" then PlayBGM('f10', true) end + if GAME.height <= -1800 and not STAT.greenClicker then + STAT.greenClicker = true + MSG("bright", "YOU DID A THING!") + end end end else diff --git a/module/initialize.lua b/module/initialize.lua index 2c1f7260..8e73c683 100644 --- a/module/initialize.lua +++ b/module/initialize.lua @@ -1,3 +1,4 @@ +--UPDCMD = "curl -s -X GET https://api.github.com/repos/MrZ626/ZenithClicker/releases/latest" if SYSTEM == "Windows" or SYSTEM == "Linux" then SupportCurl = true elseif SYSTEM == "Android" then @@ -13,6 +14,9 @@ elseif SYSTEM == "Android" then f:close() end end +--[[if SupportCurl then + ASYNC.runCmd('checkUpdate', UPDCMD) +end]] if FILE.exist('data.luaon') then if not FILE.exist('best.luaon') then love.filesystem.write('best.luaon', love.filesystem.read('data.luaon')) @@ -20,13 +24,25 @@ if FILE.exist('data.luaon') then love.filesystem.remove('data.luaon') end if FILE.exist('conf.luaon') then love.filesystem.remove('conf.luaon') end -TABLE.update(BEST, FILE.safeLoad('best.luaon', '-luaon') or NONE) -TABLE.update(STAT, FILE.safeLoad('stat.luaon', '-luaon') or NONE) -TABLE.update(ACHV, FILE.safeLoad('achv.luaon', '-luaon') or NONE) if FILE.exist('avatar') then local suc, res = pcall(GC.newImage, 'avatar') if suc then AVATAR = res end end + +function LoadSave() + local stat = FILE.safeLoad('stat.luaon', '-luaon') + if stat then + TABLE.update(STAT, stat) + if not stat.srTimer_life then + STAT.srTimer_life, STAT.srTimer_game = nil, nil + end + end + TABLE.update(BEST, FILE.safeLoad('best.luaon', '-luaon') or NONE) + TABLE.update(ACHV, FILE.safeLoad('achv.luaon', '-luaon') or NONE) +end + +LoadSave() + function Initialize(save) if STAT.totalF10 == 0 and STAT.totalGiga > 0 then STAT.totalF10 = math.floor(STAT.totalGiga * 0.872) end if STAT.totalBonus == 0 and STAT.totalGame > 2.6 then STAT.totalBonus = STAT.totalHeight * 0.5 end @@ -273,8 +289,10 @@ function Initialize(save) SaveStat() end + GAME.refreshRev() GAME.refreshLockState() GAME.refreshPBText() + RefreshHelpText() love.window.setFullscreen(STAT.fullscreen) ApplySettings() GAME.refreshCursor() diff --git a/scene/about.lua b/scene/about.lua index 97330717..8ea6e217 100644 --- a/scene/about.lua +++ b/scene/about.lua @@ -269,12 +269,13 @@ function scene.draw() local smithyMode = TABLE.equal(GAME.getHand(true),{'eEX','eVL','eAS'}) or TABLE.equal(GAME.getHand(true),{'eEX','NH','MS','GV','eVL','DH','IN','eAS','DP'}) or TABLE.equal(GAME.getHand(true),{'eEX','rNH','rMS','rGV','eVL','rDH','rIN','eAS','rDP'}) - if GAME.mod.EX > 0 then - icon = TEXTURE.logo_old - kx, ky = .5, .5 - elseif smithyMode then + or TABLE.equal(GAME.getHand(true),{'rEX','eNH','eMS','eGV','rVL','eDH','eIN','rAS','eDP'}) + if smithyMode then icon = TEXTURE.programmingsmithy kx, ky = .3, .3 + elseif GAME.mod.EX > 0 then + icon = TEXTURE.logo_old + kx, ky = .5, .5 else icon = TEXTURE.logo kx, ky = .3, .3 @@ -409,6 +410,10 @@ scene.widgetList = { if link then SFX.play('menuconfirm') love.system.openURL(link) + if MOBILE then + CLIPBOARD.set(link) + MSG("bright", "Link copied to clipboard!") + end IssueAchv('www') end end, diff --git a/scene/achv.lua b/scene/achv.lua index 16ae3146..9c82ba93 100644 --- a/scene/achv.lua +++ b/scene/achv.lua @@ -219,7 +219,6 @@ function RefreshAchvList(canShuffle) end end end - print(TABLE.dump(overallProgress)) end local function submit(id, score, silent, realSilent) diff --git a/scene/conf.lua b/scene/conf.lua index 9b321865..6cee0beb 100644 --- a/scene/conf.lua +++ b/scene/conf.lua @@ -1,6 +1,18 @@ ---@type Zenitha.Scene local scene = {} + +-- 1. Video & Audio +-- 2. Utils +-- 3. Album +-- 4. ZCEM +local page = 1 +local maxPage = 4 +local uidList = {} ---@type ({uid: string, modTime?: string} | false)[] + +local anonUser +local resetall_cnt, resetall_anim, lastClear + local clr = { D = { COLOR.HEX '191E31FF' }, L = { COLOR.HEX '4D67A6FF' }, @@ -11,7 +23,6 @@ local clr = { } local colorRev = false local bindBuffer -MusicPlayer = false local playingBgmTitle = 'Philosophyz' local playingBgmLength = 2202.8 local playingBgmLengthStr = '22:02.8' @@ -28,7 +39,6 @@ local songList = { f9 = "Dr Ocelot - Broken Record", f10 = "petrtech - Deified Validation", tera = "Dr Ocelot - Schnellfeuer BULLET", - f1ex = "Dr Ocelot - Infernal Registration", f0r = "Dr Ocelot - Awaiting Judgement", f1r = "Dr Ocelot - Desecrated Ruins", @@ -47,6 +57,10 @@ local songList = { teral = "Trevor Smithy - Schnellfeuer BULLET Lyric Cover", terael = "Trevor Smithy - Schnellfeuer BULLET Vocal & Lyric Cover", fomg = "Ronezkj15 - Strained Endurance", + f0_EX = "Dr Ocelot - Watchful Eye (EX)", + f0r_EX = "Dr Ocelot - Awaiting Judgement (EX)", + f1_EX = "Dr Ocelot - Infernal Registration", + f1r_EX = "Dr Ocelot - Desecrated Ruins (EX)", } local bgmColors = { f1 = { COLOR.HEX 'E46A24' }, @@ -69,52 +83,224 @@ local bgmColors = { f8r = { COLOR.HEX 'F16A77' }, f9r = { COLOR.HEX '3DA878' }, f10r = { COLOR.HEX 'AD80F5' }, + + f0 = { COLOR.HEX '8C2B15' }, + f0r = { COLOR.HEX '8C2B15' }, + tera = { COLOR.HEX 'C0C0C0' }, + terar = { COLOR.HEX 'C0C0C0' }, + terae = { COLOR.HEX 'C0C0C0' }, + teral = { COLOR.HEX 'C0C0C0' }, + terael = { COLOR.HEX 'C0C0C0' }, fomg = { COLOR.HEX '00437A' }, } +local bgmHeight = { + [0] = Floors[0].top, + Floors[0].top, + Floors[1].top, + Floors[2].top, + Floors[3].top, + Floors[4].top, + Floors[5].top, + Floors[6].top, + Floors[7].top, + Floors[8].top, + Floors[9].top + 10, + Floors[9].top + 26, -- special +} + +-- ZCEM Trevor Smithy +local ZCEMclr = { + D = COLOR.DG, + L = { .15, .75, .15 }, + T = { COLOR.HEX '6FAC82FF' }, + LT = { COLOR.HEX 'B0EBCCFF' }, + cbFill = { COLOR.HEX '0B0E17FF' }, + cbFrame = { COLOR.HEX '6A82A7FF' }, +} +local bpmMode = false +local comboTimer = 0 +local combo = 0 +local leftx, rightx, leftbx, rightbx = 40, 500, 220, 685 +-- Panel size +local w, h = 900, 830 +local baseX, baseY = 800 - w / 2, 500 - h / 2 + 10 + +local descriptionIndex = 0 +local descriptionTable = { + [0] = "Press to cycle through options' descriptions.", + "GAME PLAY: Press to switch to the ALBUM. Also switches to BPM mode.", + "SPEED: Press to switch to BPM. Shows timer speed, affected by Z/eS/eI.", + "Promotion Gauge: A colored indicator of maximum XP if surge is broken.", + "Stacker Mode: Commit NOTHING to add to the stack, clear for big burst!", + "Old Transparent Card: Old version of eO. Worse with DP, but no ZP nerf.", + "Old Hitbox: Hitboxes are based on center of cards instead of visible area.", + "Use Easy Names: Mods use their Easy variants in-game, even with rDH!", + "Imperial Units: Feet and Miles used instead of Meters. No records allowed!" +} +local pieceDescriptionTable = { + [0] = "Press to cycle through options' descriptions.", + "eZ: Passive climb speed x2, Gravity Timer x2, normal damage/fatigue timer.", + "eS: Damage, fatigue, gravity timers and XP loss x0.75, normal climb speed.", + "eJ: Attack x0.5, passive climb speed x8 (x4.8 with rEX or uEX)", + "eL: XP lock increased by 5 seconds, XP leak speed x0.375", + "eT: 20% UI element opacity, stuck in Floor 1 (easier quests, timers, etc.)", + "eO: 26% card opacity, adds a colored outline if card is required.", + "eI: Assist Mode, stronger the closer cards are (excluding Close Card).", + "Ultra Reverse: Upgrades Reversed mods to Ultra Reversed, or Easy to Uneasy." +} +local startHour = os.date('%H') +local startMin = os.date('%M') +local startSec = os.date('%S') local function refreshWidgets() - scene.widgetList.account:setVisible(not MusicPlayer) - scene.widgetList.album:setVisible(MusicPlayer) - scene.widgetList.mp_prev5s:setVisible(MusicPlayer) - scene.widgetList.mp_next5s:setVisible(MusicPlayer) - scene.widgetList.mp_noLoop:setVisible(MusicPlayer) - scene.widgetList.changeAboutme:setVisible(not MusicPlayer) - scene.widgetList.changeName:setVisible(not MusicPlayer) - scene.widgetList.export:setVisible(not MusicPlayer) - scene.widgetList.audio:setVisible(not MusicPlayer) - scene.widgetList.mute:setVisible(not MusicPlayer) + for _, W in next, scene.widgetList do + W:setVisible() + local tabs = {'back', 'conf', 'utils', 'album', 'zcem'} + local zcem = {'gameplay', 'bpm', 'promotion', 'imperial', 'oldTransparentCard', 'oldHitbox', 'easyName', 'stacker', 'pieces', 'ez', 'es', 'ej', 'el', 'et', 'eo', 'ei', 'urm', 'clear', 'help2'} + if not TABLE.find(tabs, W.name) and TABLE.find(zcem, W.name) then + if GAME.ecloseCard then + if W.x < 700 then + if W.type == "checkBox" then + W.x = baseX + leftx + 20 + elseif W.type == "button" then + W.x = baseX + leftbx + 20 + else + W.x = baseX + 20 + 20 + end + else + if W.type == "checkBox" then + W.x = baseX + rightx - 20 + elseif W.type == "button" then + W.x = baseX + rightbx - 20 + end + end + W:resetPos() + else + if W.x < 700 then + if W.type == "checkBox" then + W.x = baseX + leftx + elseif W.type == "button" then + W.x = baseX + leftbx + else + W.x = baseX + 20 + end + else + if W.type == "checkBox" then + W.x = baseX + rightx + elseif W.type == "button" then + W.x = baseX + rightbx + end + end + W:resetPos() + end + if GAME.eglassCard and TABLE.find(zcem, W.name) then + if W.name and #W.name > 2 and W.type ~= "button" and W.type ~= "hint" and W.name ~= "urm" then + W.textColor = COLOR.L + end + else + if W.name and #W.name > 2 and W.type ~= "button" and W.type ~= "hint" and W.name ~= "urm" and TABLE.find(zcem, W.name) then + W.textColor = page == 4 and ZCEMclr.T or clr.T + end + end + end + end + if SongNamePlaying == 'teral' or SongNamePlaying == 'terael' then + scene.widgetList.loops:setVisible(false) + end +end + +local function timePast(t1, t2) + if not t1 then return "unknown" end + local diff = math.abs(t2 - t1) + local unit + if diff < 60 then + return "just now" + elseif diff < 3600 then + diff = math.floor(diff / 60) + unit = 'm' + elseif diff < 86400 then + diff = math.floor(diff / 3600) + unit = 'h' + elseif diff < 2592000 then + diff = math.floor(diff / 86400) + unit = 'd' + elseif diff < 31536000 then + diff = math.floor(diff / 2592000) + unit = 'mo' + else + diff = math.floor(diff / 31536000) + unit = 'y' + end + return diff .. unit .. (t2 > t1 and " ago" or " from future") +end +local function refreshUID() + anonUser = STAT.uid:sub(1, 5) == 'ANON-' + TABLE.clear(uidList) + uidList[0] = { uid = "Active Profile: " .. STAT.uid, modTime = "just now" } + for i = 1, 3 do + if FILE.exist('save' .. i) then + local dat = FILE.load('save' .. i .. "/stat.luaon") + uidList[i] = { uid = dat.uid, modTime = timePast(dat.modTime, os.time()) } + else + uidList[i] = false + end + end end +local sp = { f0 = 1, f1 = 1, f0r = 1, f1r = 1 } local function refreshSongInfo() - if not MusicPlayer then return end - playingBgmTitle = BgmPlaying == 'f0' and RevMusicMode() and songList.f0r or songList[BgmPlaying] or "Rewrite" + if sp[SongNamePlaying] then + playingBgmTitle = songList[SongNamePlaying .. (GAME.mod.EX > 0 and '_EX' or '')] + else + playingBgmTitle = songList[SongNamePlaying] or "Rewrite" + end playingBgmLength = BGM.getDuration() playingBgmLengthStr = STRING.time_simp(playingBgmLength) GAME.refreshRPC() end +-- ZCEM Trevor Smithy +local function anyPieceActive() + return GAME.nightcore or GAME.enightcore or GAME.slowmo or GAME.eslowmo or GAME.glassCard or GAME.eglassCard or GAME.fastLeak or GAME.efastLeak or GAME.invisUI or GAME.einvisUI or GAME.invisCard or GAME.einvisCard or GAME.closeCard or GAME.ecloseCard +end + +local function countPiecesActive() + return (GAME.nightcore and 1 or 0) + (GAME.enightcore and 1 or 0) + (GAME.slowmo and 1 or 0) + (GAME.eslowmo and 1 or 0) + (GAME.glassCard and 1 or 0) + (GAME.eglassCard and 1 or 0) + (GAME.fastLeak and 1 or 0) + (GAME.efastLeak and 1 or 0) + (GAME.invisUI and 1 or 0) + (GAME.einvisUI and 1 or 0) + (GAME.invisCard and 1 or 0) + (GAME.einvisCard and 1 or 0) + (GAME.closeCard and 1 or 0) + (GAME.ecloseCard and 1 or 0) +end + function scene.load() MSG.clear() bindBuffer = nil + resetall_cnt, resetall_anim, lastClear = 0, 0, false SetMouseVisible(true) if GAME.anyRev ~= colorRev then colorRev = GAME.anyRev for _, C in next, clr do C[1], C[3] = C[3], C[1] end + for _, C in next, ZCEMclr do + C[1], C[3] = C[3], C[1] + end end TASK.unlock('changeName') TASK.unlock('changeAboutme') TASK.unlock('export') TASK.unlock('import') TASK.unlock('rebind_control') + TASK.unlock('just_saved') + if STAT.stacker and STAT.promotion then + MSG("achv_badTime", "WARNING: PROMOTION and STACKER are MUTUALLY EXCLUSIVE!\nDISABLE ONE NOW OR IT WILL BE DONE AUTOMATICALLY!") + SFX.play('hyperalert') + end refreshWidgets() + GAME.refreshCurrentCombo() refreshSongInfo() + refreshUID() end --- function scene.unload() --- SaveStat() --- end +function scene.unload() + GAME.refreshCurrentCombo() +end local bindHint = { "CARD-1", @@ -154,78 +340,72 @@ local function isLegalKey(key) end function scene.keyDown(key, isRep) if isRep then return true end - if KBisDown('lctrl', 'rctrl') and (key:match('^f%d%d?$') and tonumber(key:match('%d+')) <= 10 or key == 'o' or key == 'pause' or key == 'break' or key == 't') then - if key == 'o' then key = 'fomg' end - if key == 'pause' or key == 'break' or key == 't' then key = 'tera' end - TASK.removeTask_code(Task_MusicEnd) - if KBisDown('lshift', 'rshift') then key = key .. 'r' - elseif KBisDown('lalt', 'ralt') and key == 'tera' then key = key .. 'e' end - if (key == 'terae' or key == 'tera') and (GAME.mod.EX == -1 and URM and GAME.mod.NH < 2 and GAME.mod.MS < 2 and GAME.mod.GV < 2 and GAME.mod.VL < 2 and GAME.mod.DH < 2 and GAME.mod.IN < 2 and GAME.mod.AS < 2 and GAME.mod.DP < 2) then - key = key .. 'l' - end - PlayBGM(key, true) - if not MusicPlayer then - MusicPlayer = true - refreshWidgets() - end - refreshSongInfo() - elseif key == 'escape' or (key == 'f1' and not bindBuffer) then - if bindBuffer then + if bindBuffer then + if key == 'escape' then bindBuffer = nil MSG('dark', "Keybinding cancelled") SFX.play('staffwarning') - else - SFX.play('menuclick') - SCN.back('none') - end - elseif bindBuffer and isLegalKey(key) then - if TABLE.find(bindBuffer, key) then - MSG('dark', "Keybinding should not repeat!", 1) - SFX.play('finessefault') - else - table.insert(bindBuffer, key) - if #bindBuffer >= 22 then - STAT.keybind = bindBuffer - bindBuffer = nil - SaveStat() - MSG('dark', "Keybinding updated.") - SFX.play('social_notify_major') + elseif isLegalKey(key) then + if TABLE.find(bindBuffer, key) then + MSG('dark', "Keybinding should not repeat!", 1) + SFX.play('finessefault') else - SFX.play('irs') + table.insert(bindBuffer, key) + if #bindBuffer >= 22 then + STAT.keybind = bindBuffer + bindBuffer = nil + SaveStat() + MSG('dark', "Keybinding updated.") + SFX.play('social_notify_major') + else + SFX.play('irs') + end end end - elseif MusicPlayer then - if key == 'left' then - TASK.removeTask_code(Task_MusicEnd) - BGM.set('all', 'seek', math.max(BGM.tell() - (KBisDown('lctrl', 'rctrl') and 26 or 5), 0)) - elseif key == 'right' then - TASK.removeTask_code(Task_MusicEnd) - BGM.set('all', 'seek', math.min(BGM.tell() + (KBisDown('lctrl', 'rctrl') and 26 or 5), BGM.getDuration())) - elseif key == 'home' then - TASK.removeTask_code(Task_MusicEnd) - BGM.set('all', 'seek', 0) - elseif key == 'end' then - TASK.new(Task_MusicEnd, true) - elseif key == 'space' then - BgmLooping, BgmNeedSkip = false, false + else + if key == 'escape' or key == 'f1' then + SFX.play('menuclick') + SCN.back('none') + GAME.refreshCurrentCombo() + elseif MATH.between(tonumber(key) or 0, 1, maxPage) then + local p = tonumber(key) + if p and p ~= page then + page = p + SFX.play('menuclick') + refreshWidgets() + end + elseif page == 3 then + if key == 'left' then + TASK.removeTask_code(Task_MusicEnd) + BGM.set('all', 'seek', math.max(BGM.tell() - (KBisDown('lctrl', 'rctrl') and 26 or 5), 0)) + elseif key == 'right' then + TASK.removeTask_code(Task_MusicEnd) + BGM.set('all', 'seek', math.min(BGM.tell() + (KBisDown('lctrl', 'rctrl') and 26 or 5), BGM.getDuration())) + elseif key == 'home' then + TASK.removeTask_code(Task_MusicEnd) + BGM.set('all', 'seek', 0) + elseif key == 'end' then + TASK.new(Task_MusicEnd, true) + elseif key == 'space' then + BgmLooping, BgmNeedSkip = false, false + end + return true end - return true end - ZENITHA._cursor.active=true + ZENITHA._cursor.active = true return true end scene.resize = refreshWidgets --- Panel size -local w, h = 900, 830 -local baseX, baseY = (1600 - w) / 2, (1000 - h) / 2 - local gc = love.graphics local gc_replaceTransform = gc.replaceTransform -local gc_setColor, gc_rectangle, gc_print, gc_printf = gc.setColor, gc.rectangle, gc.print, gc.printf +local gc_draw, gc_setColor, gc_rectangle = gc.draw, gc.setColor, gc.rectangle +local gc_print, gc_printf = gc.print, gc.printf local gc_ucs_move, gc_ucs_back = GC.ucs_move, GC.ucs_back local gc_setAlpha, gc_mRect, gc_mStr = GC.setAlpha, GC.mRect, GC.mStr +local gc_line, gc_circle, gc_rotate, gc_setLineWidth = gc.line, gc.circle, gc.rotate, gc.setLineWidth +local sin, cos = math.sin, math.cos local function drawSliderComponents(y, title, t1, t2, value) gc_ucs_move(0, y) @@ -245,6 +425,29 @@ local function drawSliderComponents(y, title, t1, t2, value) gc_ucs_back() end +local playing +function scene.update(dt) + if SongNamePlaying ~= playing then + refreshSongInfo() + refreshWidgets() + playing = SongNamePlaying + end + if page == 3 and (BgmPlaying == 'tera' or BgmPlaying == 'terar' or BgmPlaying == 'terae' or BgmPlaying == 'teral' or BgmPlaying == 'terael') then + GAME.height = GAME.height + dt * (BgmPlaying == 'tera' and 20 or BgmPlaying == 'terae' and 78 or BgmPlaying == 'teral' and 7 or BgmPlaying == 'terael' and 26 or 42) * (GAME.height >= 1650 and .2 or 1) + if GAME.height >= 1726 and (BgmPlaying ~= 'terae' or BgmPlaying == 'terael') or GAME.height >= 6200 then GAME.bgH, GAME.height = -30, -30 end + dt = dt * 2.6 + end + GAME.bgH = MATH.expApproach(GAME.bgH, GAME.height, dt * 1.6) + StarPS:moveTo(0, -GAME.bgH * 2 * BgScale) + StarPS:update(dt) + if not TASK.getLock('reset_all') then resetall_cnt = 0 end + resetall_anim = MATH.expApproach(resetall_anim, resetall_cnt / 16, dt * 12) + comboTimer = comboTimer - dt + if comboTimer <= 0 then + combo = 0 + end +end + function scene.draw() DrawBG(STAT.bgBrightness) @@ -252,21 +455,69 @@ function scene.draw() local playTime = 0 local beatLen = 0 local beatBar = 0 - if MusicPlayer then + if bpmMode then playTime = BGM.tell() beatLen = 60 / BgmData[BgmPlaying].bpm beatBar = BgmData[BgmPlaying].bar end + -- ClockEffect + local gravityMod = {[-1] = -6, [0] = 1, 1, 2, 3} + local gv = GAME.mod.GV + (GAME.mod.GV == 2 and URM and 1 or 0) + local clockMod = 9.57 + if GAME.enightcore or GAME.eslowmo then + gc_replaceTransform(SCR.xOy_m) + gc_rotate(-1.5708) + gc_setLineWidth(42) + local a = love.timer.getTime() + -- goal is for all hands to complete a revolution at *gravityMod* rate + local h = a*gravityMod[gv]/(3600*clockMod) + startHour/6 * 3.1416 + local m = a*gravityMod[gv]/(60*clockMod) + startMin/30 * 3.1416 + local s = a*gravityMod[gv]/clockMod + startSec/30 * 3.1416 + local o = a*gravityMod[gv]*(184/4)/clockMod -- 184 rotations per minute + local x = a*gravityMod[gv]*(240/4)/clockMod -- 240 rotations per minute + if GAME.enightcore then + gc_setColor(1, 1, 1, GAME.playing and .1 or .26) + gc_circle('line', 0, 0, 620) + gc_setColor(1, 1, 1, GAME.playing and .26 or .42) + gc_setLineWidth(26) + gc_line(0, 0, 120 * cos(h), 120 * sin(h)) + gc_setLineWidth(16) + gc_line(0, 0, 260 * cos(m), 260 * sin(m)) + gc_setLineWidth(10) + gc_line(0, 0, 420 * cos(s), 420 * sin(s)) + gc_line(0, 0, 520 * cos(o), 520 * sin(o)) + gc_line(0, 0, 600 * cos(x), 600 * sin(x)) + else + gc_setColor(1, 1, 1, GAME.playing and .1 or .26) + gc_circle('line', 0, 0, 620) + gc_setColor(1, 1, 1, GAME.playing and .26 or .42) + gc_setLineWidth(26) + gc_line(0, 0, 120 * cos(h), 120 * sin(h)) + gc_setLineWidth(16) + gc_line(0, 0, 260 * cos(m), 260 * sin(m)) + gc_setLineWidth(10) + gc_line(0, 0, 420 * cos(s), 420 * sin(s)) + end + end + -- Panel gc_replaceTransform(SCR.xOy) - gc.translate(800 - w / 2, 510 - h / 2) - if MusicPlayer then + gc.translate(baseX, baseY) + if bpmMode and (page == 3 or page == 4) then local dy = MATH.clamp(6 * math.sin(playTime / beatLen * 3.1416), -2.6, 2.6) gc.translate(0, dy) SCN.curScroll = -dy end - gc_setColor(clr.D) + gc_setColor(page == 4 and ZCEMclr.D or clr.D) + if GAME.eglassCard then + local speedMod = ((GAME.enightcore or GAME.nightcore) and 2 or 1) * (GAME.eslowmo and 0.75 or 1) * (GAME.slowmo and 0.5 or 1) + gc_setColor(bgmColors[BgmPlaying] or clr.LT) + if BgmPlaying == 'tera' or BgmPlaying == 'terar' or BgmPlaying == 'terae' or BgmPlaying == 'teral' or BgmPlaying == 'terael' then + gc_setColor(COLOR.rainbow_dark(2.6 * t * speedMod)) + end + end + gc_setAlpha(GAME.einvisCard and 0.626 or 1) gc_rectangle('fill', 0, 0, w, h) gc_setColor(0, 0, 0, .26) gc_rectangle('fill', 3, 3, w - 6, h - 6) @@ -275,29 +526,82 @@ function scene.draw() gc_setColor(1, 1, 1, .04) gc_rectangle('fill', 0, 3, 3, h + 3) - -- Sliders - drawSliderComponents(310, "EFFECT VOLUME", "QUIET (F3)", "LOUD (F3)", STAT.sfx) - drawSliderComponents(380, "MUSIC VOLUME", "QUIET (F4)", "LOUD (F4)", STAT.bgm) - drawSliderComponents(520, "CARD BRIGHTNESS", "DARK (F5)", "BRIGHT (F6)", STAT.cardBrightness) - drawSliderComponents(590, "BG BRIGHTNESS", "DARK (F7)", "BRIGHT (F8)", STAT.bgBrightness) + if GAME.efastLeak then + gc_setAlpha(1) + gc_replaceTransform(SCR.origin) + gc_setColor(0, .42, 1, (GAME.mod.EX > 0 and .62 or .42)) + gc_draw(TEXTURE.transition, 0, 0, 0, .42 / 128 * SCR.w, SCR.h) + gc_draw(TEXTURE.transition, SCR.w, 0, 0, -.42 / 128 * SCR.w, SCR.h) + gc_replaceTransform(SCR.xOy) + gc.translate(baseX, baseY) + end + + if page == 1 then + -- Sliders + drawSliderComponents(120, "EFFECT VOLUME", "QUIET (F3)", "LOUD (F3)", STAT.sfx) + drawSliderComponents(200, "MUSIC VOLUME", "QUIET (F4)", "LOUD (F4)", STAT.bgm) + drawSliderComponents(430, "CARD BRIGHTNESS", "DARK (F5)", "BRIGHT (F6)", STAT.cardBrightness) + drawSliderComponents(510, "BG BRIGHTNESS", "DARK (F7)", "BRIGHT (F8)", STAT.bgBrightness) - -- Keybind - if bindBuffer then + -- Keybind + if bindBuffer then + FONT.set(30) + gc_print("Press key for...", 600, 670, 0, .872) + gc_print(bindHint[#bindBuffer + 1], 600, 700, 0, .872) + end + elseif page == 2 then + if resetall_anim > .1 then + local t2 = MATH.iLerp(.1, 1, resetall_anim) + gc_setColor(1, 1, 1, t2 * .42) + GC.mDraw(TEXTURE.warning, w / 2, h / 2, 0, MATH.lerp(1, 2.6, t2) ^ 2.6) + GC.setLineWidth(2) + gc_setColor(1, t % .16 < .08 and 0 or 1, 0, resetall_anim * 2) + gc_mRect('line', 450, 420, 520, 140, 20) + end + gc_setColor((anonUser and -t or TASK.getLock('just_saved') or 0) % .5, 0, 0, .26) + gc_mRect('fill', 450, 420, 520, 140, 20) + gc_setColor(1, t % .16 < .08 and .2 + resetall_anim * .6 or .2, .2, resetall_anim ^ .26 * .26) + gc_mRect('fill', 450, 420, 520 * resetall_anim, 140, 20) + gc_setColor(1, 1, 1, .1) + FONT.set(50) + gc_print("0", 200, 345) FONT.set(30) - gc_print("Press key for...", 610, 680, 0, .872) - gc_print(bindHint[#bindBuffer + 1], 610, 710, 0, .872) - end + gc_setColor(clr.LT) + gc_mStr(uidList[0].uid, 450, 360) + for i = 1, 3 do + local y = 220 + 330 + (i - 1) * 90 + gc_setColor(1, 1, 1, .1) + FONT.set(50) + gc_print(i, 30, y - 45) + FONT.set(30) + gc_setColor(0, 0, 0, .26) + gc_mRect('fill', 450, y, 860, 80, 20) + gc_setColor(clr.L) + if uidList[i] then + gc_mStr(uidList[i].modTime, 140, y - 20 + 15) + gc_setColor(clr.LT) + gc_mStr(uidList[i].uid, 140, y - 20 - 15) + else + gc_mStr("[empty]", 140, y - 20) + end + end + elseif page == 3 then + -- Music player + local len = 800 + + local playTime = BGM.tell() + local beatLen = 60 / BgmData[BgmPlaying].bpm + local beatBar = BgmData[BgmPlaying].bar - -- Music player info - if MusicPlayer then - local len = 620 - gc_ucs_move(140, 202) + gc_ucs_move(50, 120) + -- Time FONT.set(30) gc_setColor(clr.T) gc_print(STRING.time_simp(playTime), 0, 49, 0, .626) gc_print(playingBgmLengthStr, len - 45, 49, 0, .626) + -- Repeat marks local data = BgmData[BgmPlaying] if BgmLooping then if data.loop[1] == 0 then @@ -308,6 +612,7 @@ function scene.draw() end end + -- Progress bar gc_setColor(clr.L) gc_rectangle('fill', 0, 46, len, 4) if BgmPlaying == 'tera' or BgmPlaying == 'terar' or BgmPlaying == 'terae' or BgmPlaying == 'teral' or BgmPlaying == 'terael' then @@ -503,17 +808,34 @@ function scene.draw() gc_mStr(lyric, (len - 200 + 4 * MATH.max(STAT.sfx,50)) / 2, height) gc_mStr(hlyric, (len - 200 + 4 * MATH.max(STAT.sfx,50)) / 2, height - 40) else - gc_setColor(bgmColors[BgmPlaying] or clr.LT) + gc_setColor(bgmColors[SongNamePlaying]) end gc_rectangle('fill', 0, 46, len * playTime / playingBgmLength, 4) + -- Ambient Glow + gc.push('transform') + gc_replaceTransform(SCR.origin) + if BgmPlaying == 'tera' or BgmPlaying == 'terar' then + gc_setAlpha(.42) + else + gc_setAlpha(.2 + .06 * math.sin(playTime / beatLen * 1.5708)) + end + gc_draw(TEXTURE.transition, 0, 0, 0, .42 / 128 * SCR.w, SCR.h) + gc_draw(TEXTURE.transition, SCR.w, 0, 0, -.42 / 128 * SCR.w, SCR.h) + gc.pop() + + -- Title + gc_setAlpha(1) gc_mStr(playingBgmTitle, len / 2, 0) - gc_setColor(1, 1, 1, .35 - .26 * math.sin(playTime / (beatBar * beatLen) * 3.1416)) + if not (BgmPlaying == 'tera' or BgmPlaying == 'terar') then + gc_setColor(1, 1, 1, .35 - .26 * math.sin(playTime / (beatBar * beatLen) * 3.1416)) + end gc_mStr(playingBgmTitle, len / 2, 0) gc_setColor(clr.LT) gc_setAlpha(.26) gc_printf(data.meta, len / 2, 56, 2 * len, 'center', 0, .42, .42, len) + -- Skip marks if BgmNeedSkip then local alpha = .26 + .62 * (-2.6 * t % 1) gc_setColor(COLOR.C) @@ -528,82 +850,264 @@ function scene.draw() -- Top bar & title gc_replaceTransform(SCR.xOy_u) - gc_setColor(clr.D) + gc_setColor(page == 4 and ZCEMclr.D or clr.D) + gc_setAlpha(GAME.einvisUI and 0.626 or 1) gc_rectangle('fill', -1300, 0, 2600, 70) - gc_setColor(clr.L) - gc_setAlpha(.626) + gc_setColor(page == 4 and ZCEMclr.L or clr.L) + gc_setAlpha(GAME.einvisUI and 0.262 or .626) gc_rectangle('fill', -1300, 70, 2600, 3) gc_replaceTransform(SCR.xOy_ul) - gc_setColor(clr.L) + gc_setColor(page == 4 and ZCEMclr.L or clr.L) + gc_setAlpha(GAME.einvisUI and 0.626 or 1) FONT.set(50) if GAME.anyRev then - gc_print("CONFIG", 15, 68, 0, 1, -1) + gc_print(page == 4 and "ZCEM SETTINGS" or "CONFIG", 15, 68, 0, 1, -1) else - gc_print("CONFIG", 15, 0) + gc_print(page == 4 and "ZCEM SETTINGS" or "CONFIG", 15, 0) end -- Bottom bar & text gc_replaceTransform(SCR.xOy_d) - gc_setColor(clr.D) + gc_setColor(page == 4 and ZCEMclr.D or clr.D) + gc_setAlpha(GAME.einvisUI and 0.626 or 1) gc_rectangle('fill', -1300, 0, 2600, -50) - gc_setColor(clr.L) - gc_setAlpha(.626) + gc_setColor(page == 4 and ZCEMclr.L or clr.L) + gc_setAlpha(GAME.einvisUI and 0.262 or .626) gc_rectangle('fill', -1300, -50, 2600, -3) gc_replaceTransform(SCR.xOy_dl) - gc_setColor(clr.L) + gc_setColor(page == 4 and ZCEMclr.L or clr.L) + gc_setAlpha(GAME.einvisUI and 0.626 or 1) FONT.set(30) - gc_print("TWEAK YOUR SETTINGS FOR A BETTER CLICKING EXPERIENCE", 15, -45, 0, .85, 1) + gc_print("TWEAK YOUR SETTINGS FOR A BETTER " .. (page == 4 and "MODDED" or "CLICKING") .. " EXPERIENCE", 15, -45, 0, .85, 1) end -scene.widgetList = { - -- ALBUM - WIDGET.new { - name = 'album', +function scene.overDraw() + -- BPM/Speed Indicator + local data = BgmData[BgmPlaying] + local bpm = data.bpm + local speedMod = 1 + if GAME.nightcore then + bpm = bpm * 2 + speedMod = speedMod * 2.6 + end + if GAME.enightcore then + bpm = bpm * 2 + end + if GAME.slowmo then + bpm = bpm / 2 + end + if GAME.eslowmo then + bpm = bpm * 0.70711 + speedMod = speedMod * 0.75 + end + if GAME.ecloseCard then + speedMod = speedMod * 2 + end + if GAME.mod.GV == -1 then + bpm = bpm * 0.70711 + elseif GAME.mod.GV == 1 then + bpm = bpm * 1.05946 + elseif GAME.mod.GV == 2 then + if not URM then + bpm = bpm * 1.12246 + else + bpm = bpm * 1.18921 + end + end + local M = GAME.mod + if (M.EX == -1 and URM and M.NH < 2 and M.MS < 2 and M.GV < 2 and M.VL < 2 and M.DH < 2 and M.IN < 2 and M.AS < 2 and M.DP < 2) then + bpm = bpm * 1.01455 + end + local playTime = 0 + local beatLen = 0 + local dy = 0 + local t = love.timer.getTime() + if bpmMode and (page == 4 or page == 3) then + playTime = BGM.tell() + beatLen = 60 / BgmData[BgmPlaying].bpm + dy = MATH.clamp(6 * math.sin(playTime / beatLen * 3.1416), -2.6, 2.6) + end + if page == 4 then + if bpmMode then + local bpmString = "BPM: "..tostring(MATH.floor(bpm*100)/100) + gc_setColor(BgmPlaying ~= 'f0' and bgmColors[BgmPlaying] or ZCEMclr.LT) + if BgmPlaying == 'tera' or BgmPlaying == 'terar' or BgmPlaying == 'terae' or BgmPlaying == 'teral' or BgmPlaying == 'terael' then + gc_setColor(COLOR.rainbow_light(2.6 * t * bpm/240)) + end + gc_setAlpha(1) + FONT.set(65) + gc_print(bpmString, 835 - (GAME.ecloseCard and 20 or 0), 110 + dy) + else + local speedString = "SPEED: "..tostring(MATH.floor(speedMod*100)/100) .. "x" + gc_setColor(BgmPlaying ~= 'f0' and bgmColors[BgmPlaying] or ZCEMclr.LT) + if BgmPlaying == 'tera' or BgmPlaying == 'terar' or BgmPlaying == 'terae' or BgmPlaying == 'teral' or BgmPlaying == 'terael' then + gc_setColor(COLOR.rainbow_light(2.6 * t * bpm/240)) + end + gc_setAlpha(1) + FONT.set(65) + gc_print(speedString, 835 - (GAME.ecloseCard and 20 or 0), 110 + dy) + end + if countPiecesActive() > 1 then + gc_setColor(COLOR.R) + gc_setAlpha(1) + FONT.set(50) + gc_print("MULTIPLE PIECES!!!", 770 - (GAME.ecloseCard and 20 or 0), baseY + 338 + dy) + GAME.refreshCurrentCombo() + else + GAME.multiplePiecesActive = false + GAME.refreshCurrentCombo() + end + end + if URM then + gc_replaceTransform(SCR.origin) + gc_setColor(.42, 0, 0, .35) + gc_draw(TEXTURE.pixel, 0, 0, 0, SCR.w, SCR.h) + gc_setColor(0, 0, 0, GAME.mod.EX == 2 and .62 or .42) + gc_draw(TEXTURE.darkCorner, 0, 0, 0, SCR.w / 128, SCR.h / 128) + end +end + +local pageVisFunc = {} +for p = 1, maxPage do pageVisFunc[p] = function() return page == p end end + +-- Page 1 +local videoY = baseY + 360 +local page1 = { + -- Audio + WIDGET.new { -- title type = 'text', alignX = 'left', - text = "ALBUM", + text = "AUDIO", color = clr.T, fontSize = 50, x = baseX + 30, y = baseY + 50, }, - WIDGET.new { - name = 'mp_prev5s', type = 'button', - x = baseX + 230, y = baseY + 115, w = 380, h = 50, - color = clr.L, - fontSize = 30, textColor = clr.LT, text = "BACK 5S", - sound_hover = 'menutap', - onClick = function() - TASK.removeTask_code(Task_MusicEnd) - BGM.set('all', 'seek', math.max(BGM.tell() - 5, 0)) + WIDGET.new { -- sfx + type = 'slider', + x = baseX + 240 + 85, y = baseY + 110, w = 400, + axis = { 0, 100, 10 }, + frameColor = 'dD', fillColor = clr.D, + disp = function() return STAT.sfx end, + code = function(value) + STAT.sfx = value + ApplySettings() end, - visibleFunc = FALSE, + sound_drag = 'rotate', }, - WIDGET.new { - name = 'mp_next5s', type = 'button', - x = baseX + 640, y = baseY + 115, w = 380, h = 50, - color = clr.L, - fontSize = 30, textColor = clr.LT, text = "FORWARD 5S", - sound_hover = 'menutap', - onClick = function() - TASK.removeTask_code(Task_MusicEnd) - BGM.set('all', 'seek', math.min(BGM.tell() + 5, BGM.getDuration())) + WIDGET.new { -- bgm + type = 'slider', + x = baseX + 240 + 85, y = baseY + 190, w = 400, + axis = { 0, 100, 10 }, + frameColor = 'dD', fillColor = clr.D, + disp = function() return STAT.bgm end, + code = function(value) + STAT.bgm = value + ApplySettings() end, - visibleFunc = FALSE, + sound_drag = 'rotate', + }, + WIDGET.new { -- mute + type = 'checkBox', + fillColor = clr.cbFill, + frameColor = clr.cbFrame, + textColor = clr.T, text = "MUTE ON UNFOCUS", + x = baseX + 55, y = baseY + 280, + disp = function() return STAT.autoMute end, + code = function() STAT.autoMute = not STAT.autoMute end, + }, + -- Video + WIDGET.new { -- title + type = 'text', alignX = 'left', + text = "VIDEO", + color = clr.T, + fontSize = 50, + x = baseX + 30, y = videoY + 0, + }, + WIDGET.new { -- card brightness + type = 'slider', + x = baseX + 240 + 85, y = videoY + 60, w = 400, + axis = { 80, 100, 5 }, + frameColor = 'dD', fillColor = clr.D, + disp = function() return STAT.cardBrightness end, + code = function(value) STAT.cardBrightness = value end, + sound_drag = 'rotate', + }, + WIDGET.new { -- bg brightness + type = 'slider', + x = baseX + 240 + 85, y = videoY + 140, w = 400, + axis = { 30, 80, 10 }, + frameColor = 'dD', fillColor = clr.D, + disp = function() return STAT.bgBrightness end, + code = function(value) STAT.bgBrightness = value end, + sound_drag = 'rotate', + }, + WIDGET.new { -- fancy + type = 'checkBox', + fillColor = clr.cbFill, + frameColor = clr.cbFrame, + textColor = clr.T, text = "FANCY BACKGROUND (F9)", + x = baseX + 55, y = videoY + 230, + disp = function() return STAT.bg end, + code = WIDGET.c_pressKey 'f9', + }, + WIDGET.new { -- star + type = 'checkBox', + fillColor = clr.cbFill, + frameColor = clr.cbFrame, + textColor = clr.T, text = "STAR FORCE (F10)", + x = baseX + 55, y = videoY + 300, + disp = function() return not STAT.syscursor end, + code = WIDGET.c_pressKey 'f10', + }, + WIDGET.new { -- fullscreen + type = 'checkBox', + fillColor = clr.cbFill, + frameColor = clr.cbFrame, + textColor = clr.T, text = "FULLSCREEN (F11)", + x = baseX + 55, y = videoY + 370, + disp = function() return STAT.fullscreen end, + code = WIDGET.c_pressKey 'f11', }, + -- Keybind WIDGET.new { - name = 'mp_noLoop', type = 'button', - x = baseX + 230, y = baseY + 185, w = 380, h = 50, + type = 'button', + x = baseX + 730, y = baseY + 770, w = 260, h = 50, color = clr.L, - fontSize = 30, textColor = clr.LT, text = "NO REPEAT MARKS", - sound_hover = 'menutap', + fontSize = 30, textColor = clr.LT, text = "REBIND KEY", onClick = function() - BgmLooping, BgmNeedSkip = false, false + if bindBuffer then + bindBuffer = {} + SFX.play('b2bcharge_danger', .8) + else + -- MSG.clear() + if TASK.lock('rebind_control', 12) then + SFX.play('notify') + MSG('dark', { + "Current Keybinding:\n" .. + table.concat(TABLE.sub(STAT.keybind, 1, 9), ', ') .. "\n" .. + table.concat(TABLE.sub(STAT.keybind, 10, 18), ', ') .. "\n" .. + "Commit: " .. STAT.keybind[19] .. "\n" .. + "Reset: " .. STAT.keybind[20] .. "\n" .. + "Click L/R: " .. STAT.keybind[21] .. ", " .. STAT.keybind[22] .. "\n", + COLOR.F, "PRESS AGAIN TO REBIND\n", + COLOR.LD, "(F1-F12 ` Tab Ctrl Alt are not allowed)" + }, + 12 + ) + else + TASK.unlock('rebind_control') + bindBuffer = {} + SFX.play('b2bcharge_danger', .8) + end + end end, - visibleFunc = FALSE, }, +} - -- ACCOUNT - WIDGET.new { - name = 'account', +-- Page 2 +local profY = baseY + 220 +local page2 = { + -- Account + WIDGET.new { -- title type = 'text', alignX = 'left', text = "ACCOUNT", color = clr.T, @@ -612,11 +1116,9 @@ scene.widgetList = { }, WIDGET.new { name = 'changeName', type = 'button', - x = baseX + 230, y = baseY + 115, w = 380, h = 50, + x = baseX + 230, y = baseY + 130, w = 380, h = 50, color = clr.L, fontSize = 30, textColor = clr.LT, text = "CHANGE USERNAME", - sound_hover = 'menutap', - sound_release = 'menuclick', onClick = function() -- MSG.clear() local newName = CLIPBOARD.get() @@ -631,39 +1133,36 @@ scene.widgetList = { return end TASK.unlock('changeName') - repeat - newName = newName:upper() - if #newName < 3 or #newName > 16 or newName:find('[^A-Z0-9_%-]') then - MSG('dark', "New name must be 3-16 characters long and contain the following: A-Z, 0-9, -, _") - break - end - if newName == STAT.uid then - MSG('dark', "New name is the same as the old one.") - break - end - if newName:match('^ANON[-_]') then - MSG('dark', "You can’t enter ANON as your new name.") - break - end - STAT.uid = newName - SaveStat() - SFX.play('supporter') - MSG('dark', "Your name was changed to " .. STAT.uid) - if SCN.cur == 'stat' then RefreshProfile() end - IssueAchv('identity') + newName = newName:upper() + if #newName < 3 or #newName > 16 or newName:find('[^A-Z0-9_%-]') then + MSG('dark', "New name must be 3-16 characters long and contain the following: A-Z, 0-9, -, _") + SFX.play('staffwarning') return - until true - SFX.play('staffwarning') + end + if newName == STAT.uid then + MSG('dark', "New name is the same as the old one.") + SFX.play('staffwarning') + return + end + if newName:match('^ANON[-_]') then + MSG('dark', "You can’t enter ANON as your new name.") + SFX.play('staffwarning') + return + end + STAT.uid = newName + SaveStat() + SFX.play('supporter') + MSG('dark', "Your name was changed to " .. STAT.uid) + if SCN.cur == 'stat' then RefreshProfile() end + refreshUID() + IssueAchv('identity') end, - visibleFunc = TRUE, }, WIDGET.new { name = 'changeAboutme', type = 'button', - x = baseX + 640, y = baseY + 115, w = 380, h = 50, + x = baseX + 640, y = baseY + 130, w = 380, h = 50, color = clr.L, fontSize = 30, textColor = clr.LT, text = "CHANGE ABOUT ME", - sound_hover = 'menutap', - sound_release = 'menuclick', onClick = function() -- MSG.clear() local newText = CLIPBOARD.get() @@ -701,15 +1200,20 @@ scene.widgetList = { until true SFX.play('staffwarning') end, - visibleFunc = TRUE, + }, + -- Profile + WIDGET.new { -- title + type = 'text', alignX = 'left', + text = "PROFILE", + color = clr.T, + fontSize = 50, + x = baseX + 30, y = profY + 0, }, WIDGET.new { name = 'export', type = 'button', - x = baseX + 230, y = baseY + 185, w = 380, h = 50, + x = baseX + 230, y = profY + 80, w = 380, h = 50, color = clr.L, fontSize = 30, textColor = clr.LT, text = "EXPORT PROGRESS", - sound_hover = 'menutap', - sound_release = 'menuclick', onClick = function() -- MSG.clear() if TestMode then @@ -727,15 +1231,12 @@ scene.widgetList = { MSG('dark', "Progress exported!") SFX.play('social_notify_minor') end, - visibleFunc = TRUE, }, WIDGET.new { name = 'import', type = 'button', - x = baseX + 640, y = baseY + 185, w = 380, h = 50, + x = baseX + 640, y = profY + 80, w = 380, h = 50, color = clr.L, fontSize = 30, textColor = clr.LT, text = "IMPORT PROGRESS", - sound_hover = 'menutap', - sound_release = 'menuclick', onClick = function() -- MSG.clear() local data = CLIPBOARD.get():filterASCII():trim() @@ -762,25 +1263,6 @@ scene.widgetList = { elseif data == 'repo' then SFX.play('menuconfirm') love.system.openURL("https://github.com/MrZ626/ZenithClicker") - elseif data == 'mp' or data == 'music' then - if (GAME.mod.EX == -1 and GAME.mod.VL == -1 and GAME.mod.AS == -1 and (GAME.mod.NH == 0 and GAME.mod.MS == 0 and GAME.mod.GV == 0 and GAME.mod.DH == 0 and GAME.mod.IN == 0 and GAME.mod.DP == 0)) and ACHV.programmer_gamer then - PlayBGM(URM and 'terael' or 'terae', false) - elseif (GAME.mod.EX == -1 and URM and GAME.mod.NH < 2 and GAME.mod.MS < 2 and GAME.mod.GV < 2 and GAME.mod.VL < 2 and GAME.mod.DH < 2 and GAME.mod.IN < 2 and GAME.mod.AS < 2 and GAME.mod.DP < 2) then - PlayBGM('teral', false) - else - if not BGM.isPlaying() or MusicPlayer then return end - end - MusicPlayer = true - refreshWidgets() - refreshSongInfo() - elseif songList[data] then - TASK.removeTask_code(Task_MusicEnd) - PlayBGM(data, true) - if not MusicPlayer then - MusicPlayer = true - refreshWidgets() - end - refreshSongInfo() elseif data == 'UseAltName' then UseAltName() SFX.play('social_dm') @@ -975,151 +1457,809 @@ scene.widgetList = { SFX.play('social_notify_major') end, }, - - -- AUDIO WIDGET.new { + name = 'resetall', type = 'button', + x = baseX + 450, y = profY + 220, w = 260, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "RESET ALL", + onClick = function() + if not (uidList[1] or uidList[2] or uidList[3]) then + SFX.play('staffwarning') + MSG('dark', "You must have at least 1 backup before resetting all progress!") + return + end + local instaReset = anonUser or TASK.getLock('just_saved') + if TASK.lock('reset_all', 2.6) then + resetall_cnt = 0 + lastClear = false + SFX.play('hyperalert') + if instaReset then + MSG('warn', "Reset all progress? Press again to confirm.", 2.6) + else + MSG('info', "Reset all progress? Spam to confirm.", 2.6) + end + return + end + if not instaReset and not TASK.forceLock('reset_all', 1) and resetall_cnt < 16 then + resetall_cnt = resetall_cnt + 1 + local spin = MATH.roll(.26) + local clear = spin and 's' .. math.random(2) or 'c' .. math.random(2, 4) + SFX.play(spin and 'clearspin' or clear == 'c4' and 'clearquad' or 'clearline') + SFX.play('combo_' .. resetall_cnt .. ((clear == 's2' or clear == 'c4') and '_power' or '')) + if GAME.mod.AS == 1 then + if clear == lastClear then + for _ = 1, 2 do SFX.play('wound') end + resetall_cnt = math.max(resetall_cnt - 2, 0) + elseif MATH.roll(.26) then + SFX.play('wound_repel') + end + elseif GAME.mod.AS == 2 then + if clear == lastClear then + for _ = 1, 3 do SFX.play('wound') end + TASK.unlock('reset_all') + SCN.back('none') + end + end + lastClear = clear + return + end + FILE.delete('stat.luaon') + FILE.delete('achv.luaon') + FILE.delete('best.luaon') + TASK.unlock('reset_all') + if not instaReset then SFX.play('combo_16_power') end + SFX.play('clearquad') + SFX.play('inject') + SFX.play('thunder' .. math.random(6)) + MSG.clear() + SCN._pop() + SCN.swapTo('joining', 'fade', true) + end, + }, +} +local function saveSlot(i) + if TestMode then + SFX.play('staffwarning') + MSG('dark', "You are not a good person.") + return + end + if uidList[i] and STAT.uid ~= uidList[i].uid then + SFX.play('staffwarning') + MSG('dark', "For safety, you can only update a backup with same username", 4.2) + return + end + TASK.unlock('save_slot' .. i) + TASK.lock('just_saved', 10) + SaveStat() + FILE.createDirectory('save' .. i) + FILE.copy('stat.luaon', 'save' .. i .. '/stat.luaon') + FILE.copy('achv.luaon', 'save' .. i .. '/achv.luaon') + FILE.copy('best.luaon', 'save' .. i .. '/best.luaon') + uidList[i] = { uid = STAT.uid, modTime = "just now" } + SFX.play('allclear') + MSG('check', "Progress backed up to slot " .. i .. "!", 2.6) + WIDGET._reset() +end +local function loadSlot(i) + if TASK.lock('load_slot' .. i, 2.6) then + SFX.play('hyperalert') + MSG('warn', "Load from slot " .. i .. "? Current save will be overwritten. Press again to confirm.", 4.2) + return + end + TASK.unlock('load_slot' .. i) + FILE.copy('save' .. i .. '/stat.luaon', 'stat.luaon') + FILE.copy('save' .. i .. '/achv.luaon', 'achv.luaon') + FILE.copy('save' .. i .. '/best.luaon', 'best.luaon') + SFX.play('levelup'); SFX.play('levelup') + SCN._pop() + SCN.swapTo('joining', 'fade', true) +end +local function clearSlot(i) + if TASK.lock('clear_slot' .. i, 2.6) then + SFX.play('hyperalert') + MSG('warn', "Clear slot " .. i .. "? This action cannot be undone. Press again to confirm.", 4.2) + return + end + TASK.unlock('clear_slot' .. i) + TASK.unlock('just_saved') + FILE.delete('save' .. i) + uidList[i] = false + SFX.play('clearquad') + SFX.play('inject') + SFX.play('thunder' .. math.random(6)) + MSG.clear() + WIDGET._reset() +end +for i = 1, 3 do + local y = profY + 330 + (i - 1) * 90 + TABLE.append(page2, { + WIDGET.new { + name = 'save' .. i, type = 'button', + x = baseX + 355, y = y, w = 160, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "BACKUP", + onClick = function() saveSlot(i) end, + }, + WIDGET.new { + name = 'load' .. i, type = 'button', + x = baseX + 555, y = y, w = 160, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "LOAD", + onClick = function() loadSlot(i) end, + visibleFunc = function() return page == 2 and uidList[i] end, + }, + WIDGET.new { + name = 'clear' .. i, type = 'button', + x = baseX + 755, y = y, w = 160, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "CLEAR", + onClick = function() clearSlot(i) end, + visibleFunc = function() return page == 2 and uidList[i] end, + }, + }) +end + +-- Page 3 +local albumY = baseY + 250 +local page3 = { + -- Album + WIDGET.new { -- title type = 'text', alignX = 'left', - name = 'audio', - text = "AUDIO", + text = "ALBUM", color = clr.T, fontSize = 50, - x = baseX + 30, y = baseY + 250, + x = baseX + 30, y = baseY + 50, }, - WIDGET.new { - name = 'mute', - type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "MUTE ON UNFOCUS", - x = baseX + 562, y = baseY + 255, - disp = function() return STAT.autoMute end, - code = function() STAT.autoMute = not STAT.autoMute end, + WIDGET.new { -- -30s + type = 'button', + x = baseX + 130, y = albumY, w = 150, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "-30s", + onClick = function() + TASK.removeTask_code(Task_MusicEnd) + BGM.set('all', 'seek', math.max(BGM.tell() - 30, 0)) + end, }, - WIDGET.new { - type = 'slider', - x = baseX + 240 + 85, y = baseY + 310, w = 400, - axis = { 0, 100, 10 }, - frameColor = 'dD', fillColor = clr.D, - disp = function() return STAT.sfx end, - code = function(value) - STAT.sfx = value - ApplySettings() + WIDGET.new { -- -5s + type = 'button', + x = baseX + 330, y = albumY, w = 150, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "-5s", + onClick = function() + TASK.removeTask_code(Task_MusicEnd) + BGM.set('all', 'seek', math.max(BGM.tell() - 5, 0)) end, - sound_drag = 'rotate', }, - WIDGET.new { - type = 'slider', - x = baseX + 240 + 85, y = baseY + 380, w = 400, - axis = { 0, 100, 10 }, - frameColor = 'dD', fillColor = clr.D, - disp = function() return STAT.bgm end, - code = function(value) - STAT.bgm = value - ApplySettings() + WIDGET.new { -- +5s + type = 'button', + x = baseX + 540, y = albumY, w = 150, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "+5s", + onClick = function() + TASK.removeTask_code(Task_MusicEnd) + BGM.set('all', 'seek', math.min(BGM.tell() + 5, BGM.getDuration())) end, - sound_drag = 'rotate', }, + WIDGET.new { -- +30s + type = 'button', + x = baseX + 740, y = albumY, w = 150, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "+30s", + onClick = function() + TASK.removeTask_code(Task_MusicEnd) + BGM.set('all', 'seek', math.min(BGM.tell() + 30, BGM.getDuration())) + end, + }, + WIDGET.new { -- no loop + name = 'loops', type = 'button', + x = baseX + 450, y = albumY + 80, w = 200, h = 50, + color = clr.L, + fontSize = 30, textColor = clr.LT, text = "NO LOOPS", + onClick = function() + BgmLooping, BgmNeedSkip = false, false + end, + }, +} +local function albumBtn(param) + table.insert(page3, WIDGET.new(TABLE.update({ + type = 'button', + w = 65, + fontSize = 30, + textColor = 'D', + }, param))) +end +for i = 0, 10 do + albumBtn { + x = baseX + 75 + 75 * i, y = baseY + 450, + color = bgmColors['f' .. i], + text = "" .. i, + onClick = function() + GAME.height = bgmHeight[i] + PlayBGM('f' .. i) + end, + visibleFunc = function() + return page == 3 and STAT.maxFloor >= i + end, + } + albumBtn { + x = baseX + 75 + 75 * i, y = baseY + 530, + color = bgmColors['f' .. i .. 'r'], + text = "R" .. i, + onClick = function() + GAME.height = (bgmHeight[i] + bgmHeight[i + 1]) / 2 + PlayBGM('f' .. i .. 'r') + end, + visibleFunc = function() return page == 3 and STAT.maxFloor >= 10 and TABLE.findAll(GAME.completion, 2) end, + } +end +albumBtn { + x = baseX + 450 - 200, y = baseY + 670, w = 150, h = 60, + color = bgmColors.tera, + text = "TERA", + onClick = function() + PlayBGM('tera') + end, + visibleFunc = function() return page == 3 and ACHV.blazing_speed end, +} +albumBtn { + x = baseX + 450, y = baseY + 670, w = 150, h = 60, + color = bgmColors.fomg, + fontSize = 50, + text = "FΩ", + onClick = function() + GAME.height = 6200 + PlayBGM('fomg') + end, + visibleFunc = function() return page == 3 and STAT.maxHeight >= 6200 end, +} +albumBtn { + x = baseX + 450 + 200, y = baseY + 670, w = 150, h = 60, + color = bgmColors.terar, + text = "TERAR", + onClick = function() + PlayBGM('terar') + end, + visibleFunc = function() return page == 3 and ACHV.blazing_speed and BEST.highScore.rEX >= Floors[9].top end, +} +albumBtn { + x = baseX + 450 - 200, y = baseY + 750, w = 150, h = 60, + color = bgmColors.tera, + text = "TERAL", + onClick = function() + PlayBGM('teral') + refreshSongInfo() + end, + visibleFunc = function() return page == 3 and ACHV.uneasy end, +} +albumBtn { + x = baseX + 450, y = baseY + 750, w = 150, h = 60, + color = bgmColors.tera, + text = "TERAEL", + onClick = function() + PlayBGM('terael') + refreshSongInfo() + end, + visibleFunc = function() return page == 3 and ACHV.uneasy and ACHV.programmer_gamer and ACHV.programmer_gamer >= 1650 end, +} +albumBtn { + x = baseX + 450 + 200, y = baseY + 750, w = 150, h = 60, + color = bgmColors.tera, + text = "TERAE", + onClick = function() + PlayBGM('terae') + refreshSongInfo() + end, + visibleFunc = function() return page == 3 and ACHV.programmer_gamer and ACHV.programmer_gamer >= 1650 end, +} - -- VIDEO - WIDGET.new { - name = 'video', +-- Page 4 +local page4 = { + WIDGET.new { -- Game Play + name = 'gameplay', type = 'button', + x = baseX + 220, y = baseY + 60, w = 410, h = 70, + color = ZCEMclr.T, + sound_hover = 'menutap', + fontSize = 50, text = "GAME PLAY", textColor = ZCEMclr.LT, + onClick = function() + bpmMode = true + refreshWidgets() + IssueAchv('music_man') + love.keypressed('3') + end, + }, + -- BPM button is shared with MP options + WIDGET.new { -- Promotion + name = 'promotion', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = ZCEMclr.T, text = "PROMOTION GAUGE", + x = baseX + 40, y = baseY + 60 + 80, + disp = function() return STAT.promotion end, + code = function() + local multiple = GAME.multiplePiecesActive + MSG.clear() + STAT.promotion = not STAT.promotion + MSG('dark', "Rank Promotion Gauge: " .. (STAT.promotion and "ON" or "OFF")) + if STAT.stacker and STAT.promotion then + STAT.stacker = false + MSG('dark', "STACKER and PROMOTION GAUGE are MUTUALLY EXCLUSIVE!") + SFX.play('no') + else + SFX.play('social_dm') + end + GAME.multiplePiecesActive = false + SaveStat() + if multiple then GAME.multiplePiecesActive = true end + end, + }, + WIDGET.new { -- Imperial + name = 'imperial', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = ZCEMclr.T, text = "IMPERIAL UNITS", + x = baseX + 500, y = baseY + 60 + 240, + disp = function() return STAT.imperial end, + code = function() + local multiple = GAME.multiplePiecesActive + MSG.clear() + STAT.imperial = not STAT.imperial + SFX.play('social_dm') + MSG('dark', "Imperial Units: " .. (STAT.imperial and "ON" or "OFF")) + GAME.multiplePiecesActive = false + SaveStat() + if multiple then GAME.multiplePiecesActive = true end + end, + }, + WIDGET.new { -- Old Transparent Card + name = 'oldTransparentCard', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = ZCEMclr.T, text = "OLD TRANSPARENT CARD", + x = baseX + 40, y = baseY + 60 + 160, + disp = function() return STAT.oldTransparentCard end, + code = function() + local multiple = GAME.multiplePiecesActive + MSG.clear() + STAT.oldTransparentCard = not STAT.oldTransparentCard + SFX.play('social_dm') + MSG('dark', "Transparent Card: " .. (STAT.oldTransparentCard and "V1.0/1.1" or "V1.2+")) + GAME.multiplePiecesActive = false + SaveStat() + if multiple then GAME.multiplePiecesActive = true end + end, + }, + WIDGET.new { -- Old Hitbox + name = 'oldHitbox', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = ZCEMclr.T, text = "OLD HITBOX", + x = baseX + 500, y = baseY + 60 + 160, + disp = function() return STAT.oldHitbox end, + code = function() + local multiple = GAME.multiplePiecesActive + MSG.clear() + STAT.oldHitbox = not STAT.oldHitbox + MSG('dark', "Force old hitbox: " .. (STAT.oldHitbox and "ON" or "OFF")) + SFX.play(STAT.oldHitbox and 'social_online' or 'social_offline') + GAME.multiplePiecesActive = false + SaveStat() + if multiple then GAME.multiplePiecesActive = true end + end, + }, + WIDGET.new { -- Use Easy Names + name = 'easyName', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = ZCEMclr.T, text = "USE EASY NAMES", + x = baseX + 40, y = baseY + 60 + 240, + disp = function() return STAT.easyName end, + code = function() + local multiple = GAME.multiplePiecesActive + MSG.clear() + STAT.easyName = not STAT.easyName + SFX.play('social_dm') + MSG('dark', "Easy Names In-Game: " .. (STAT.easyName and "ON" or "OFF")) + GAME.multiplePiecesActive = false + SaveStat() + if multiple then GAME.multiplePiecesActive = true end + end, + }, + WIDGET.new { -- Stacker + name = 'stacker', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = ZCEMclr.T, text = "STACKER MODE", + x = baseX + 500, y = baseY + 60 + 80, + disp = function() return STAT.stacker end, + code = function() + local multiple = GAME.multiplePiecesActive + MSG.clear() + STAT.stacker = not STAT.stacker + MSG('dark', "Stacker Mode: " .. (STAT.stacker and "ON" or "OFF")) + if STAT.stacker and STAT.promotion then + STAT.promotion = false + SFX.play('no') + MSG('dark', "STACKER and PROMOTION GAUGE are MUTUALLY EXCLUSIVE!") + else + SFX.play('social_dm') + end + GAME.multiplePiecesActive = false + SaveStat() + if multiple then GAME.multiplePiecesActive = true end + end, + }, + WIDGET.new { -- BPM/Speed Button + name = 'bpm', type = 'button', + x = baseX + 685, y = baseY + 60, w = 410, h = 70, + color = ZCEMclr.T, + sound_hover = 'menutap', + fontSize = 50, text = "", textColor = ZCEMclr.LT, + onClick = function() + bpmMode = not bpmMode + end, + }, + -- PIECE EFFECTS + WIDGET.new { -- pieces + name = 'pieces', type = 'text', alignX = 'left', - text = "VIDEO", - color = clr.T, + text = "PIECE EFFECTS", + color = ZCEMclr.T, fontSize = 50, - x = baseX + 30, y = baseY + 460, + x = baseX + 20, y = baseY + 370, }, - WIDGET.new { - type = 'slider', - x = baseX + 240 + 85, y = baseY + 520, w = 400, - axis = { 80, 100, 5 }, - frameColor = 'dD', fillColor = clr.D, - disp = function() return STAT.cardBrightness end, - code = function(value) STAT.cardBrightness = value end, - sound_drag = 'rotate', + WIDGET.new { -- ez + name = 'ez', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.lR, text = "eZ - Nightcore+", + x = baseX + 40, y = baseY + 50 + 400, + disp = function() return GAME.enightcore end, + code = function() + MSG.clear() + TASK.removeTask_code(Task_MusicEnd) + if not GAME.enightcore and anyPieceActive() then + SFX.play('damage_alert') + MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") + GAME.multiplePiecesActive = true + else + SFX.play('social_dm') + end + GAME.enightcore = not GAME.enightcore + MSG('dark', "eZ: " .. (GAME.enightcore and "ON" or "OFF")) + RefreshBGM(mode) + end, }, - WIDGET.new { - type = 'slider', - x = baseX + 240 + 85, y = baseY + 590, w = 400, - axis = { 30, 80, 10 }, - frameColor = 'dD', fillColor = clr.D, - disp = function() return STAT.bgBrightness end, - code = function(value) STAT.bgBrightness = value end, - sound_drag = 'rotate', + WIDGET.new { -- es + name = 'es', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.lG, text = "eS - Slow-mo+", + x = baseX + 500, y = baseY + 50 + 400, + disp = function() return GAME.eslowmo end, + code = function() + MSG.clear() + TASK.removeTask_code(Task_MusicEnd) + if not GAME.eslowmo and anyPieceActive() then + SFX.play('damage_alert') + MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") + GAME.multiplePiecesActive = true + else + SFX.play('social_dm') + end + GAME.eslowmo = not GAME.eslowmo + MSG('dark', "eS: " .. (GAME.eslowmo and "ON" or "OFF")) + RefreshBGM(mode) + end, }, - WIDGET.new { - type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "FANCY BACKGROUND (F9)", - x = baseX + 55, y = baseY + 670, - disp = function() return STAT.bg end, - code = WIDGET.c_pressKey 'f9', + WIDGET.new { -- ej + name = 'ej', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.lB, text = "eJ - Glass Card+", + x = baseX + 40, y = baseY + 50 + 480, + disp = function() return GAME.eglassCard end, + code = function() + MSG.clear() + TASK.removeTask_code(Task_MusicEnd) + if not GAME.eglassCard and anyPieceActive() then + SFX.play('damage_alert') + MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") + GAME.multiplePiecesActive = true + else + SFX.play('social_dm') + end + GAME.eglassCard = not GAME.eglassCard + MSG('dark', "eJ: " .. (GAME.eglassCard and "ON" or "OFF")) + refreshWidgets() + RefreshBGM(mode) + end, }, - WIDGET.new { - type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "STAR FORCE (F10)", - x = baseX + 55, y = baseY + 730, - disp = function() return not STAT.syscursor end, - code = WIDGET.c_pressKey 'f10', + WIDGET.new { -- el + name = 'el', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.lO, text = "eL - Slow Leak", + x = baseX + 500, y = baseY + 50 + 480, + disp = function() return GAME.efastLeak end, + code = function() + MSG.clear() + TASK.removeTask_code(Task_MusicEnd) + if not GAME.efastLeak and anyPieceActive() then + SFX.play('damage_alert') + MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") + GAME.multiplePiecesActive = true + else + SFX.play('social_dm') + end + GAME.efastLeak = not GAME.efastLeak + MSG('dark', "eL: " .. (GAME.efastLeak and "ON" or "OFF")) + RefreshBGM(mode) + end, }, - WIDGET.new { - type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "FULLSCREEN (F11)", - x = baseX + 55, y = baseY + 790, - disp = function() return STAT.fullscreen end, - code = WIDGET.c_pressKey 'f11', + WIDGET.new { -- eT + name = 'et', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.lM, text = "eT - Transparent UI", + x = baseX + 40, y = baseY + 50 + 560, + disp = function() return GAME.einvisUI end, + code = function() + MSG.clear() + TASK.removeTask_code(Task_MusicEnd) + if not GAME.einvisUI and anyPieceActive() then + SFX.play('damage_alert') + MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") + GAME.multiplePiecesActive = true + else + SFX.play('social_dm') + end + GAME.einvisUI = not GAME.einvisUI + MSG('dark', "eT: " .. (GAME.einvisUI and "ON" or "OFF")) + RefreshBGM(mode) + end, }, - - -- KEYBIND - WIDGET.new { - name = 'keybind', type = 'button', - x = baseX + 740, y = baseY + 790, w = 260, h = 50, - color = clr.L, - fontSize = 30, textColor = clr.LT, text = "REBIND KEY", + WIDGET.new { -- eo + name = 'eo', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.lY, text = "eO - Transparent Card", + x = baseX + 500, y = baseY + 50 + 560, + disp = function() return GAME.einvisCard end, + code = function() + MSG.clear() + TASK.removeTask_code(Task_MusicEnd) + if not GAME.einvisCard and anyPieceActive() then + SFX.play('damage_alert') + MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") + GAME.multiplePiecesActive = true + else + SFX.play('social_dm') + end + GAME.einvisCard = not GAME.einvisCard + MSG('dark', "eO: " .. (GAME.einvisCard and "ON" or "OFF")) + RefreshBGM(mode) + end, + }, + WIDGET.new { -- ei + name = 'ei', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.lC, text = "eI - Closer Card", + x = baseX + 40, y = baseY + 50 + 640, + disp = function() return GAME.ecloseCard end, + code = function() + MSG.clear() + TASK.removeTask_code(Task_MusicEnd) + if not GAME.ecloseCard and anyPieceActive() then + SFX.play('damage_alert') + MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") + GAME.multiplePiecesActive = true + else + SFX.play('social_dm') + end + GAME.ecloseCard = not GAME.ecloseCard + MSG('dark', "eI: " .. (GAME.ecloseCard and "ON" or "OFF")) + refreshWidgets() + RefreshBGM(mode) + end, + }, + WIDGET.new { -- urm + name = 'urm', type = 'checkBox', + fillColor = ZCEMclr.cbFill, + frameColor = ZCEMclr.cbFrame, + textColor = COLOR.R, text = "Ultra Reverse", + x = baseX + 500, y = baseY + 50 + 640, + disp = function() return URM end, + code = function() + URM = not URM + SFX.play(URM and 'exchange' or 'undo') + GAME.hardMode = GAME.mod.EX > 0 or GAME.anyRev and not URM + GAME.refreshLayout() + GAME.refreshUltra() + --GAME.refreshCurrentCombo() + GAME.refreshPBText() + RefreshBGM(mode) + GAME.refreshRPC() + RefreshHelpText() + end, + }, + WIDGET.new { -- Clear Button + name = 'clear', type = 'button', + x = baseX + 220, y = baseY + 60 + 720, w = 410, h = 70, + color = ZCEMclr.T, sound_hover = 'menutap', - sound_release = 'menuclick', + fontSize = 50, text = "CLEAR PIECES", textColor = ZCEMclr.LT, onClick = function() - if bindBuffer then - bindBuffer = {} - SFX.play('b2bcharge_danger', .8) + if anyPieceActive() or URM then + SFX.play('allclear') + MSG('dark', 'All Clear') else - -- MSG.clear() - if TASK.lock('rebind_control', 12) then - SFX.play('notify') - MSG('dark', { - "Current Keybinding:\n" .. - table.concat(TABLE.sub(STAT.keybind, 1, 9), ', ') .. "\n" .. - table.concat(TABLE.sub(STAT.keybind, 10, 18), ', ') .. "\n" .. - "Commit: " .. STAT.keybind[19] .. "\n" .. - "Reset: " .. STAT.keybind[20] .. "\n" .. - "Click L/R: " .. STAT.keybind[21] .. ", " .. STAT.keybind[22] .. "\n", - COLOR.F, "PRESS AGAIN TO REBIND\n", - COLOR.LD, "(F1-F12 ` Tab Ctrl Alt are not allowed)" - }, - 12 - ) + if combo == 0 or (STAT.unlockAll and ACHV.lazy_bastard) then + MSG.clear() + MSG("dark", "What do you want me to deselect?") + SFX.play('no') + elseif combo < 16 then + local str = '' + for i = 1, combo do + str = str .. '?' + end + MSG.clear() + MSG("dark", str) + SFX.play('combo_' .. combo) else - TASK.unlock('rebind_control') - bindBuffer = {} - SFX.play('b2bcharge_danger', .8) + if not ACHV.lazy_bastard then + IssueAchv('lazy_bastard') + else + MSG("dark", "Fine, okay, everything is unlocked now.") + end + GAME.unlockAll() + SFX.play('combo_16') end + combo = combo + 1 + comboTimer = 3 end + URM = false + GAME.nightcore = false + GAME.slowmo = false + GAME.glassCard = false + GAME.fastLeak = false + GAME.invisUI = false + GAME.invisCard = false + GAME.closeCard = false + GAME.enightcore = false + GAME.eslowmo = false + GAME.eglassCard = false + GAME.efastLeak = false + GAME.einvisUI = false + GAME.einvisCard = false + GAME.ecloseCard = false + GAME.multiplePiecesActive = false + GAME.pieceEffectID = #PieceData + GAME.hardMode = GAME.mod.EX > 0 or GAME.anyRev and not URM + GAME.refreshLayout() + GAME.refreshUltra() + GAME.refreshCurrentCombo() + GAME.refreshPBText() + RefreshBGM(mode) + GAME.refreshRPC() + RefreshHelpText() + refreshWidgets() end, }, + WIDGET.new { -- normal piece button + name = 'help2', type = 'button', + x = baseX + 685, y = baseY + 60 + 720, w = 410, h = 70, + color = ZCEMclr.T, + sound_hover = 'menutap', + fontSize = 50, text = "CYCLE PIECES", textColor = ZCEMclr.LT, + onClick = function() + GAME.pieceEffectID = (GAME.pieceEffectID or 0) % #PieceData + 1 + if GAME.pieceEffectID <= #PieceData - 1 then + local piece = ('zsjltoi'):sub(GAME.pieceEffectID, GAME.pieceEffectID) + SFX.play(piece, 1, 0, Tone(6)) + if GAME.pieceEffectID > 7 then + SFX.play('combo_'..(GAME.pieceEffectID - 7)..'_power', 1, 0, Tone(0)) + end + else + SFX.play('allclear') + end + + --for i = 1, 7 do + -- Trevor Smithy + for i = 1, #PieceData - 1 do + GAME[PieceData[i].id] = GAME.pieceEffectID == i + end + + GAME.refreshLayout() + RefreshBGM() + GAME.refreshRPC() + -- Trevor Smithy + GAME.refreshCurrentCombo() + refreshWidgets() + GAME.multiplePiecesActive = false + MSG({ + cat = 'dark', + str = PieceData[GAME.pieceEffectID].popup, + time = 1.2 + }) + end, + }, + WIDGET.new { + name = 'description', type = 'hint', + pos = { 0.98, 1 }, x = 0, y = -25, w = 45, cornerR = 20, + color = ZCEMclr.L, textColor = ZCEMclr.L, + fontSize = 40, text = "?", -- Dynamic text + sound_hover = 'menutap', + labelPos = 'left', + floatFontSize = 20, + floatText = descriptionTable[descriptionIndex], -- Dynamic text + onPress = function() + local piece = love.mouse.isDown('2') or love.keyboard.isDown('lctrl', 'rctrl') + descriptionIndex = descriptionIndex + 1 + if descriptionIndex > #descriptionTable then descriptionIndex = 1 end + scene.widgetList.description.floatText = piece and pieceDescriptionTable[descriptionIndex] or descriptionTable[descriptionIndex] + if descriptionIndex == 2 and bpmMode then scene.widgetList.description.floatText = "BPM: Shows current song's BPM, affected by Z/S/eZ/eS/all GVs/ueEX." end + scene.widgetList.description:reset() + end + }, +} + +-- Apply visibility functions if not set +for _, W in next, page1 do W.visibleFunc = W.visibleFunc or pageVisFunc[1] end +for _, W in next, page2 do W.visibleFunc = W.visibleFunc or pageVisFunc[2] end +for _, W in next, page3 do W.visibleFunc = W.visibleFunc or pageVisFunc[3] end +for _, W in next, page4 do W.visibleFunc = W.visibleFunc or pageVisFunc[4] end +-- Tabs +local tab = { WIDGET.new { name = 'back', type = 'button', pos = { 0, 0 }, x = 60, y = 140, w = 160, h = 60, color = { .15, .15, .15 }, - sound_hover = 'menutap', fontSize = 30, text = " BACK", textColor = 'DL', onClick = function() love.keypressed('escape') end, }, + WIDGET.new { + name = 'conf', type = 'button', + pos = { 1, 0 }, x = -60, y = 140, w = 160, h = 60, + color = { COLOR.HEX '383838' }, + fontSize = 30, text = "CONF ", textColor = 'DL', + onClick = function() love.keypressed('1') end, + }, + WIDGET.new { + name = 'utils', type = 'button', + pos = { 1, 0 }, x = -60, y = 230, w = 160, h = 60, + color = { COLOR.HEX '383838' }, + fontSize = 30, text = "UTILS ", textColor = 'DL', + onClick = function() love.keypressed('2') end, + }, + WIDGET.new { + name = 'album', type = 'button', + pos = { 1, 0 }, x = -60, y = 320, w = 160, h = 60, + color = { COLOR.HEX '383838' }, + fontSize = 30, text = "ALBUM ", textColor = 'DL', + onClick = function() love.keypressed('3') end, + }, + WIDGET.new { + name = 'zcem', type = 'button', + pos = { 1, 0 }, x = -60, y = 410, w = 160, h = 60, + color = 'DG', + sound_hover = 'menutap', + fontSize = 30, text = "ZCEM ", textColor = { .15, .75, .15 }, + onPress = function() love.keypressed('4') end, + onClick = function() love.keyreleased('4') end, + }, } +for _, W in next, page1 do if W.type == 'button' or W.type == 'checkBox' then W.sound_hover, W.sound_release = 'menutap', 'menuclick' end end +for _, W in next, page2 do if W.type == 'button' or W.type == 'checkBox' then W.sound_hover, W.sound_release = 'menutap', 'menuclick' end end +for _, W in next, page3 do if W.type == 'button' or W.type == 'checkBox' then W.sound_hover = 'menutap' end end -- Album buttons should be quiet + +scene.widgetList = {} +TABLE.append(scene.widgetList, page1) +TABLE.append(scene.widgetList, page2) +TABLE.append(scene.widgetList, page3) +TABLE.append(scene.widgetList, page4) +TABLE.append(scene.widgetList, tab) + return scene diff --git a/scene/joining.lua b/scene/joining.lua index d4edd421..3f6b51ad 100644 --- a/scene/joining.lua +++ b/scene/joining.lua @@ -1,10 +1,13 @@ ---@type Zenitha.Scene local scene = {} -local t1, t2 = .26, .42 +local initialized = false +local t1, t2 function scene.load() + t1, t2 = .26, .42 love.keyboard.setKeyRepeat(false) + TEXTS.load:set(SCN.args[1] and "Welcome Back." or "JOINING ROOM...") end scene.keyDown = TRUE @@ -15,21 +18,46 @@ function scene.update(dt) elseif t1 > 0 then t1 = t1 - dt if t1 <= 0 then - TEXTS.load:set("GETTING READY TO SPECTATE...") - BGM.setMaxSources(42) - BGM.load(FILE.load('data/bgm.lua', '-luaon')) - SFX.load('assets/sfx.ogg', FILE.load('data/sfx.lua', '-luaon')) - for i = 1, 9 do - SFX.load('garbagewindup_'..i, 'assets/windup_'..i..'.ogg') + if SCN.args[1] then + GAME.bgH, GAME.height = 0, 0 + GAME.finishTera = false + for k in next, GAME.completion do + GAME.completion[k] = 0 + GAME.mod[k] = 0 + if Cards[k].active then + Cards[k]:setActive(true) + end + end + for i = 1, #PieceData - 1 do + GAME[PieceData[i].id] = false + end + INIT_DATA() + LoadSave() + URM = false + GAME.pieceEffectID = 0 + GAME.floor = 0 + Initialize(true) + GAME.clearResultStat() + end + if not initialized then + BGM.setMaxSources(42) + BGM.load(FILE.load('data/bgm.lua', '-luaon')) + SFX.load('assets/sfx.ogg', FILE.load('data/sfx.lua', '-luaon')) + for i = 1, 9 do + SFX.load('garbagewindup_'..i, 'assets/windup_'..i..'.ogg') + end + TASK.new(Daemon_Slow) + TASK.new(Daemon_Fast) + TEXTS.load:set("GETTING READY TO SPECTATE...") + + ---@diagnostic disable-next-line + local _, _, _, _ = TEXTURE.panel.glass_a, TEXTURE.panel.glass_b, TEXTURE.panel.throb_a, TEXTURE.panel.throb_b + for i = 2, 9 do TEXTURE.towerBG[i]:setWrap('mirroredrepeat', 'mirroredrepeat') end + TEXTURE.towerBG[1]:setWrap('mirroredrepeat', 'clampzero') + TEXTURE.towerBG[10]:setWrap('mirroredrepeat', 'clampzero') + _, _ = TEXTURE.moon, TEXTURE.stars + initialized = true end - TASK.new(Daemon_Slow) - TASK.new(Daemon_Fast) - ---@diagnostic disable-next-line - local _, _, _, _ = TEXTURE.panel.glass_a, TEXTURE.panel.glass_b, TEXTURE.panel.throb_a, TEXTURE.panel.throb_b - for i = 2, 9 do TEXTURE.towerBG[i]:setWrap('mirroredrepeat', 'mirroredrepeat') end - TEXTURE.towerBG[1]:setWrap('mirroredrepeat', 'clampzero') - TEXTURE.towerBG[10]:setWrap('mirroredrepeat', 'clampzero') - _, _ = TEXTURE.moon, TEXTURE.stars end elseif t2 > 0 then t2 = t2 - dt diff --git a/scene/tower.lua b/scene/tower.lua index 53001990..665de8c4 100644 --- a/scene/tower.lua +++ b/scene/tower.lua @@ -38,6 +38,7 @@ local function switchVisitor(bool) love.mouse.setRelativeMode(bool) ZENITHA._cursor.active = not bool for _, W in next, scene.widgetList do W:setVisible(not bool) end + scene.widgetList.help2:setVisible() if usingTouch then scene.widgetList.help:setVisible(true) end if bool then IssueAchv('zenith_traveler') end TABLE.clear(HoldingButtons) @@ -299,14 +300,12 @@ local function keyTrigger(key) SFX.play('combo_16' .. (power and '_power' or ''), 1, 0, Tone((power and (combo-1)/5 or 0))) scene.widgetList.easy.x = -100 scene.widgetList.easy:resetPos() - if power then + if power and not GAME.playing then GAME.fallout = true scene.widgetList.stat.x = -100 scene.widgetList.stat:resetPos() scene.widgetList.achv.x = -100 scene.widgetList.achv:resetPos() - scene.widgetList.zcem.x = 100 - scene.widgetList.zcem:resetPos() scene.widgetList.about.x = 100 scene.widgetList.about:resetPos() scene.widgetList.conf.x = 100 @@ -385,17 +384,6 @@ local function keyTrigger(key) comboTimer = 3 end GAME.anyChange = false - elseif key == 'f15' then - if GAME.playing or GAME.badTime then - SFX.play('no') - else - if URM and M.VL == 2 and not UltraVlCheck('zcem') then return end - SFX.play('menuhit1') - SCN.go('zcem', 'none') - end - local W = scene.widgetList.zcem - W._pressTime = W._pressTimeMax * 2 - W._hoverTime = W._hoverTimeMax end end end @@ -569,7 +557,7 @@ function scene.mouseDown(x, y, k) switchVisitor(false) return true end - if k == 3 then return true end + if k == 3 and GAME.playing then return true end HoldingButtons['mouse' .. k] = true GAME.nixPrompt('keep_no_mouse') GAME.noMouseOrSpin = false @@ -590,7 +578,7 @@ function scene.mouseUp(x, y, k) if GAME.zenithTraveler then return end GAME.nixPrompt('keep_no_mouse') GAME.noMouseOrSpin = false - if k == 3 then return end + if k == 3 and GAME.playing then return end --if getBtnPressed() > 1 + (URM and M.VL == 2 and 0 or floor(M.VL / 2)) then return end if getBtnPressed() > (URM and M.VL == 2 and 0 or M.VL == -1 and 0 or floor(M.VL / 2)) then return end @@ -929,7 +917,7 @@ function DrawBG(brightness, showRuler) end -- Cover - local f10CoverAlpha = GAME.zenithTraveler and icLerp(1660, 1650, GAME.bgH) or 1 - GAME.floorTime / 2.6 + local f10CoverAlpha = max(icLerp(1660, 1650, GAME.bgH), 1 - (love.timer.getTime() - GAME.f10Time) / 2.6) if f10CoverAlpha > 0 then gc_setColor(.5, .5, .5, f10CoverAlpha) gc_rectangle('fill', 0, 0, SCR.w, SCR.h) @@ -1864,6 +1852,16 @@ function scene.overDraw() gc_draw(TEXTS.credit, -5, d, 0, .872, .872, TEXTS.credit:getDimensions()) end + -- Speedrun Timer + if STAT.srTimer_life then + gc_replaceTransform(SCR.xOy_dl) + setFont(30) + gc_setColor(TextColor) + gc_setAlpha(.42) + TEXTS.srTimer:set(STRING.time(STAT.srTimer_game) .. "/ " .. STRING.time_simp(STAT.srTimer_life)) + gc_draw(TEXTS.srTimer, 7, -70 + GAME.uiHide * 30) + end + -- Card Info if not GAME.playing and FloatOnCard then local C = Cards[FloatOnCard] @@ -2090,7 +2088,7 @@ function scene.overDraw() -- Fastleak cover if GAME.fastLeak then gc_replaceTransform(SCR.origin) - gc_setColor(0, 1, .42, (GAME.playing and .626 or 1) * (M.EX > 0 and .62 or .42)) + gc_setColor(0, 1, .42, (GAME.playing and .626 or 1) * ((M.EX > 0 or M.DP == 2) and .62 or .42)) gc_draw(TEXTURE.transition, 0, 0, 0, .42 / 128 * SCR.w, SCR.h) gc_draw(TEXTURE.transition, SCR.w, 0, 0, -.42 / 128 * SCR.w, SCR.h) end @@ -2220,15 +2218,6 @@ scene.widgetList = { onPress = function() love.keypressed('f2') end, onClick = function() love.keyreleased('f2') end, }, - WIDGET.new { - name = 'zcem', type = 'button', - pos = { 1, 0 }, x = -60, y = 410, w = 160, h = 60, - color = 'DG', - sound_hover = 'menutap', - fontSize = 30, text = "ZCEM ", textColor = { .15, .75, .15 }, - onPress = function() love.keypressed('f15') end, - onClick = function() love.keyreleased('f15') end, - }, WIDGET.new { name = 'start', type = 'button', pos = { .5, .5 }, y = -170, w = 800, h = 200, @@ -2342,19 +2331,22 @@ scene.widgetList = { SFX.play('no') end else - PieceSFXID = (PieceSFXID or 0) % #PieceData + 1 - if PieceSFXID < #PieceData then - local piece = ('zsjltoi'):sub(PieceSFXID, PieceSFXID) + if (k == 3 or kbIsDown('lalt', 'ralt') or next(easyHold)) and (GAME.pieceEffectID < 7 or GAME.pieceEffectID == #PieceData) then + GAME.pieceEffectID = 7 + end + GAME.pieceEffectID = GAME.pieceEffectID % #PieceData + 1 + if GAME.pieceEffectID < #PieceData then + local piece = ('zsjltoi'):sub(GAME.pieceEffectID, GAME.pieceEffectID) SFX.play(piece, 1, 0, Tone(6)) - if PieceSFXID > 7 then - SFX.play('combo_'..(PieceSFXID - 7)..'_power', 1, 0, Tone(0)) + if GAME.pieceEffectID > 7 then + SFX.play('combo_'..(GAME.pieceEffectID - 7)..'_power', 1, 0, Tone(0)) end else SFX.play('allclear') end for i = 1, #PieceData - 1 do - GAME[PieceData[i].id] = PieceSFXID == i + GAME[PieceData[i].id] = GAME.pieceEffectID == i end GAME.refreshLayout() @@ -2365,7 +2357,7 @@ scene.widgetList = { GAME.multiplePiecesActive = false MSG({ cat = 'dark', - str = PieceData[PieceSFXID].popup, + str = PieceData[GAME.pieceEffectID].popup, time = 1.2 }) end diff --git a/scene/zcem.lua b/scene/zcem.lua deleted file mode 100644 index a44cc1bb..00000000 --- a/scene/zcem.lua +++ /dev/null @@ -1,1082 +0,0 @@ ----@type Zenitha.Scene -local scene = {} - -local clr = { - D = COLOR.DG, - L = { .15, .75, .15 }, - T = { COLOR.HEX '6FAC82FF' }, - LT = { COLOR.HEX 'B0EBCCFF' }, - cbFill = { COLOR.HEX '0B0E17FF' }, - cbFrame = { COLOR.HEX '6A82A7FF' }, -} -local colorRev = false -local bpmMode = false -local lastNonTera = 'f0' -local mode = '' -local comboTimer = 0 -local combo = 0 -local leftx, rightx, leftbx, rightbx = 40, 500, 220, 685 -local descriptionIndex = 0 -local descriptionTable = { - [0] = "Press to cycle through options' descriptions.", - "GAME PLAY: Press to switch to Music Player mode. Also switches to BPM.", - "SPEED: Press to switch to BPM. Shows timer speed, affected by Z/eS/eI.", - "Promotion Gauge: A colored indicator of maximum XP if surge is broken.", - "Stacker Mode: Commit NOTHING to add to the stack, clear for big burst!", - "Old Transparent Card: Old version of eO. Worse with DP, but no ZP nerf.", - "Old Hitbox: Hitboxes are based on center of cards instead of visible area.", - "Use Easy Names: Mods use their Easy variants in-game, even with rDH!", - "Imperial Units: Feet and Miles used instead of Meters. No records allowed!" -} -local mpDescriptionTable = { - [0] = "Press to cycle through options' descriptions.", - "MUSIC PLAY: Press to switch to Gameplay mode. Doesn't switch from BPM.", - "BPM: Shows current song's BPM, affected by Z/S/eZ/eS/all GVs/ueEX.", - "PREV TRACK: Selects previous floor's track. Doesn't include TERASPEED.", - "NEXT TRACK: Selects next floor's track. Doesn't include TERASPEED.", - "TERASPEED: Enables TERASPEED theme, required for UNEASY and SMITHY.", - "REVERSE: Enables REVERSE variant, disables UNEASY and SMITHY.", - "UNEASY: Enables lyrics. Requires TERASPEED. Check CONF to see lyrics.", - "SMITHY: Enables vocals. Requires TERASPEED. Enabled with eEX+eVL+eAS.", -} -local pieceDescriptionTable = { - [0] = "Press to cycle through options' descriptions.", - "eZ: Passive climb speed x2, Gravity Timer x2, normal damage/fatigue timer.", - "eS: Damage, fatigue, gravity timers and XP loss x0.75, normal climb speed.", - "eJ: Attack x0.5, passive climb speed x8 (x4.8 with rEX or uEX)", - "eL: XP lock increased by 5 seconds, XP leak speed x0.375", - "eT: 20% UI element opacity, stuck in Floor 1 (easier quests, timers, etc.)", - "eO: 26% card opacity, adds a colored outline if card is required.", - "eI: Assist Mode, stronger the closer cards are (excluding Close Card).", - "Ultra Reverse: Upgrades Reversed mods to Ultra Reversed, or Easy to Uneasy." -} -local startHour = os.date('%H') -local startMin = os.date('%M') -local startSec = os.date('%S') -local bgmColors = { - f1 = { COLOR.HEX 'E46A24' }, - f2 = { COLOR.HEX 'F1CC80' }, - f3 = { COLOR.HEX '804200' }, - f4 = { COLOR.HEX '8E1D1D' }, - f5 = { COLOR.HEX 'B8C1C1' }, - f6 = { COLOR.HEX 'EAA380' }, - f7 = { COLOR.HEX '70B5E1' }, - f8 = { COLOR.HEX 'F16A77' }, - f9 = { COLOR.HEX '3DA878' }, - f10 = { COLOR.HEX 'AD80F5' }, - f1r = { COLOR.HEX 'E46A24' }, - f2r = { COLOR.HEX 'F1CC80' }, - f3r = { COLOR.HEX '804200' }, - f4r = { COLOR.HEX '8E1D1D' }, - f5r = { COLOR.HEX 'B8C1C1' }, - f6r = { COLOR.HEX 'EAA380' }, - f7r = { COLOR.HEX '70B5E1' }, - f8r = { COLOR.HEX 'F16A77' }, - f9r = { COLOR.HEX '3DA878' }, - f10r = { COLOR.HEX 'AD80F5' }, - fomg = { COLOR.HEX '00437A' }, -} - --- Panel size -local w, h = 900, 830 -local baseX, baseY = (1600 - w) / 2, (1000 - h) / 2 - -local gc = love.graphics -local gc_replaceTransform = gc.replaceTransform -local gc_setColor, gc_rectangle, gc_print, gc_printf = gc.setColor, gc.rectangle, gc.print, gc.printf -local gc_ucs_move, gc_ucs_back = GC.ucs_move, GC.ucs_back -local gc_setAlpha, gc_mRect, gc_mStr = GC.setAlpha, GC.mRect, GC.mStr -local gc_draw = gc.draw -local gc_line, gc_circle, gc_rotate, gc_setLineWidth = gc.line, gc.circle, gc.rotate, gc.setLineWidth -local sin, cos = math.sin, math.cos - -local function refreshWidgets() - scene.widgetList.gameplay:setVisible(not MusicPlayer) - scene.widgetList.promotion:setVisible(not MusicPlayer) - scene.widgetList.imperial:setVisible(not MusicPlayer) - scene.widgetList.oldTransparentCard:setVisible(not MusicPlayer) - scene.widgetList.oldHitbox:setVisible(not MusicPlayer) - scene.widgetList.easyName:setVisible(not MusicPlayer) - scene.widgetList.stacker:setVisible(not MusicPlayer) - scene.widgetList.musicplay:setVisible(MusicPlayer) - scene.widgetList.prevtrack:setVisible(MusicPlayer) - scene.widgetList.nexttrack:setVisible(MusicPlayer) - scene.widgetList.tera:setVisible(MusicPlayer) - scene.widgetList.reverse:setVisible(MusicPlayer) - scene.widgetList.uneasy:setVisible(MusicPlayer) - scene.widgetList.smithyMode:setVisible(MusicPlayer) - for _, W in next, scene.widgetList do - if W.name ~= 'back' then - if GAME.ecloseCard then - if W.x < 700 then - if W.type == "checkBox" then - W.x = baseX + leftx + 20 - elseif W.type == "button" then - W.x = baseX + leftbx + 20 - else - W.x = baseX + 20 + 20 - end - else - if W.type == "checkBox" then - W.x = baseX + rightx - 20 - elseif W.type == "button" then - W.x = baseX + rightbx - 20 - end - end - W:resetPos() - else - if W.x < 700 then - if W.type == "checkBox" then - W.x = baseX + leftx - elseif W.type == "button" then - W.x = baseX + leftbx - else - W.x = baseX + 20 - end - else - if W.type == "checkBox" then - W.x = baseX + rightx - elseif W.type == "button" then - W.x = baseX + rightbx - end - end - W:resetPos() - end - if GAME.eglassCard then - if #W.name > 2 and W.type ~= "button" and W.type ~= "hint" and W.name ~= "urm" then - W.textColor = COLOR.L - end - else - if #W.name > 2 and W.type ~= "button" and W.type ~= "hint" and W.name ~= "urm" then - W.textColor = clr.T - end - end - end - end - scene.widgetList.description.floatText = MusicPlayer and mpDescriptionTable[descriptionIndex] or descriptionTable[descriptionIndex] - scene.widgetList.description:reset() -end - -local function anyPieceActive() - return GAME.nightcore or GAME.enightcore or GAME.slowmo or GAME.eslowmo or GAME.glassCard or GAME.eglassCard or GAME.fastLeak or GAME.efastLeak or GAME.invisUI or GAME.einvisUI or GAME.invisCard or GAME.einvisCard or GAME.closeCard or GAME.ecloseCard -end - -local function countPiecesActive() - return (GAME.nightcore and 1 or 0) + (GAME.enightcore and 1 or 0) + (GAME.slowmo and 1 or 0) + (GAME.eslowmo and 1 or 0) + (GAME.glassCard and 1 or 0) + (GAME.eglassCard and 1 or 0) + (GAME.fastLeak and 1 or 0) + (GAME.efastLeak and 1 or 0) + (GAME.invisUI and 1 or 0) + (GAME.einvisUI and 1 or 0) + (GAME.invisCard and 1 or 0) + (GAME.einvisCard and 1 or 0) + (GAME.closeCard and 1 or 0) + (GAME.ecloseCard and 1 or 0) -end - -function scene.load() - MSG.clear() - bindBuffer = nil - SetMouseVisible(true) - if GAME.anyRev ~= colorRev then - colorRev = GAME.anyRev - for _, C in next, clr do - C[1], C[3] = C[3], C[1] - end - end - if STAT.stacker and STAT.promotion then - MSG("achv_badTime", "WARNING: PROMOTION and STACKER are MUTUALLY EXCLUSIVE!\nDISABLE ONE NOW OR IT WILL BE DONE AUTOMATICALLY!") - SFX.play('hyperalert') - end - refreshWidgets() - GAME.refreshCurrentCombo() -end - -function scene.unload() - GAME.refreshCurrentCombo() -end - -function scene.update(dt) - comboTimer = comboTimer - dt - if comboTimer <= 0 then - combo = 0 - end -end - -local KBisDown = love.keyboard.isDown -function scene.keyDown(key, isRep) - if isRep then return true end - if key == 'escape' then - SFX.play('menuclick') - SCN.back('none') - GAME.refreshCurrentCombo() - end - ZENITHA._cursor.active=true - return true -end - -scene.resize = refreshWidgets - -function scene.draw() - DrawBG(STAT.bgBrightness) - - local t = love.timer.getTime() - local playTime = 0 - local beatLen = 0 - local beatBar = 0 - if MusicPlayer then - playTime = BGM.tell() - beatLen = 60 / BgmData[BgmPlaying].bpm - beatBar = BgmData[BgmPlaying].bar - end - - -- ClockEffect - local gravityMod = 1 - if GAME.mod.GV == 2 and URM then - gravityMod = 2 ^ (3/12) - elseif GAME.mod.GV == 2 then - gravityMod = 2 ^ (2/12) - elseif GAME.mod.GV == 1 then - gravityMod = 2 ^ (1/12) - elseif GAME.mod.GV == -1 then - gravityMod = 2 ^ (-6/12) - end - local clockMod = 9.57 - if GAME.enightcore or GAME.eslowmo then - gc_replaceTransform(SCR.xOy_m) - gc_rotate(-1.5708) - gc_setLineWidth(42) - local a = love.timer.getTime() - -- goal is for all hands to complete a revolution at *gravityMod* rate - local h = a*gravityMod/(3600*clockMod) + startHour/6 * 3.1416 - local m = a*gravityMod/(60*clockMod) + startMin/30 * 3.1416 - local s = a*gravityMod/clockMod + startSec/30 * 3.1416 - local o = a*gravityMod*(184/4)/clockMod -- 184 rotations per minute - local x = a*gravityMod*(240/4)/clockMod -- 240 rotations per minute - if GAME.enightcore then - gc_setColor(1, 1, 1, GAME.playing and .1 or .26) - gc_circle('line', 0, 0, 620) - gc_setColor(1, 1, 1, GAME.playing and .26 or .42) - --a = os.date('%H') / 6 * 3.1416 - gc_setLineWidth(26) - gc_line(0, 0, 120 * cos(h), 120 * sin(h)) - --a = os.date('%M') / 30 * 3.1416 - gc_setLineWidth(16) - gc_line(0, 0, 260 * cos(m), 260 * sin(m)) - --a = os.date('%S') / 30 * 3.1416 - gc_setLineWidth(10) - gc_line(0, 0, 420 * cos(s), 420 * sin(s)) - --a = love.timer.getTime() / 30 * 3.1416 * 26 - gc_line(0, 0, 520 * cos(o), 520 * sin(o)) - --a = love.timer.getTime() / 30 * 3.1416 * 60 - gc_line(0, 0, 600 * cos(x), 600 * sin(x)) - else - gc_setColor(1, 1, 1, GAME.playing and .1 or .26) - gc_circle('line', 0, 0, 620) - gc_setColor(1, 1, 1, GAME.playing and .26 or .42) - --a = os.date('%H') / 6 * 3.1416 - gc_setLineWidth(26) - gc_line(0, 0, 120 * cos(h), 120 * sin(h)) - --a = os.date('%M') / 30 * 3.1416 - gc_setLineWidth(16) - gc_line(0, 0, 260 * cos(m), 260 * sin(m)) - --a = os.date('%S') / 30 * 3.1416 - gc_setLineWidth(10) - gc_line(0, 0, 420 * cos(s), 420 * sin(s)) - end - end - - -- Panel - gc_replaceTransform(SCR.xOy) - gc.translate(800 - w / 2, 510 - h / 2) - if MusicPlayer then - local dy = MATH.clamp(6 * math.sin(playTime / beatLen * 3.1416), -2.6, 2.6) - gc.translate(0, dy) - SCN.curScroll = -dy - end - gc_setColor(clr.D) - if GAME.eglassCard then - local speedMod = ((GAME.enightcore or GAME.nightcore) and 2 or 1) * (GAME.eslowmo and 0.75 or 1) * (GAME.slowmo and 0.5 or 1) - gc_setColor(COLOR.rainbow_dark(2.6 * t * speedMod)) - end - gc_setAlpha(GAME.einvisCard and 0.626 or 1) - gc_rectangle('fill', 0, 0, w, h) - gc_setColor(0, 0, 0, GAME.einvisCard and 0.13 or .26) - gc_rectangle('fill', 3, 3, w - 6, h - 6) - gc_setColor(1, 1, 1, GAME.einvisCard and 0.05 or .1) - gc_rectangle('fill', 0, 0, w, 3) - gc_setColor(1, 1, 1, GAME.einvisCard and 0.02 or .04) - gc_rectangle('fill', 0, 3, 3, h + 3) - - if GAME.efastLeak then - gc_setAlpha(1) - gc_replaceTransform(SCR.origin) - gc_setColor(0, .42, 1, (GAME.mod.EX > 0 and .62 or .42)) - gc_draw(TEXTURE.transition, 0, 0, 0, .42 / 128 * SCR.w, SCR.h) - gc_draw(TEXTURE.transition, SCR.w, 0, 0, -.42 / 128 * SCR.w, SCR.h) - end - - -- Top bar & title - gc_replaceTransform(SCR.xOy_u) - gc_setColor(clr.D) - gc_setAlpha(GAME.einvisUI and 0.626 or 1) - gc_rectangle('fill', -1300, 0, 2600, 70) - gc_setColor(clr.L) - gc_setAlpha(GAME.einvisUI and 0.262 or .626) - gc_rectangle('fill', -1300, 70, 2600, 3) - gc_replaceTransform(SCR.xOy_ul) - gc_setColor(clr.L) - gc_setAlpha(GAME.einvisUI and 0.626 or 1) - FONT.set(50) - if GAME.anyRev then - gc_print("ZCEM SETTINGS", 15, 68, 0, 1, -1) - else - gc_print("ZCEM SETTINGS", 15, 0) - end - - -- Bottom bar & text - gc_replaceTransform(SCR.xOy_d) - gc_setColor(clr.D) - gc_setAlpha(GAME.einvisUI and 0.626 or 1) - gc_rectangle('fill', -1300, 0, 2600, -50) - gc_setColor(clr.L) - gc_setAlpha(GAME.einvisUI and 0.262 or .626) - gc_rectangle('fill', -1300, -50, 2600, -3) - gc_replaceTransform(SCR.xOy_dl) - gc_setColor(clr.L) - gc_setAlpha(GAME.einvisUI and 0.626 or 1) - FONT.set(30) - gc_print("TWEAK YOUR SETTINGS FOR A BETTER MODDED EXPERIENCE", 15, -45, 0, .85, 1) -end - -function scene.overDraw() - -- BPM/Speed Indicator - local data = BgmData[BgmPlaying] - local bpm = data.bpm - local speedMod = 1 - if GAME.nightcore then - bpm = bpm * 2 - speedMod = speedMod * 2.6 - end - if GAME.enightcore then - bpm = bpm * 2 - end - if GAME.slowmo then - bpm = bpm / 2 - end - if GAME.eslowmo then - bpm = bpm * 0.70711 - speedMod = speedMod * 0.75 - end - if GAME.ecloseCard then - speedMod = speedMod * 2 - end - if GAME.mod.GV == -1 then - bpm = bpm * 0.70711 - elseif GAME.mod.GV == 1 then - bpm = bpm * 1.05946 - elseif GAME.mod.GV == 2 then - if not URM then - bpm = bpm * 1.12246 - else - bpm = bpm * 1.18921 - end - end - local M = GAME.mod - if (M.EX == -1 and URM and M.NH < 2 and M.MS < 2 and M.GV < 2 and M.VL < 2 and M.DH < 2 and M.IN < 2 and M.AS < 2 and M.DP < 2) then - bpm = bpm * 1.01455 - end - local playTime = 0 - local beatLen = 0 - local dy = 0 - local t = love.timer.getTime() - if MusicPlayer then - playTime = BGM.tell() - beatLen = 60 / BgmData[BgmPlaying].bpm - dy = MATH.clamp(6 * math.sin(playTime / beatLen * 3.1416), -2.6, 2.6) - end - if bpmMode then - local bpmString = "BPM: "..tostring(MATH.floor(bpm*100)/100) - gc_setColor(bgmColors[BgmPlaying] or clr.LT) - if BgmPlaying == 'tera' or BgmPlaying == 'terar' or BgmPlaying == 'terae' or BgmPlaying == 'teral' or BgmPlaying == 'terael' then - gc_setColor(COLOR.rainbow_light(2.6 * t * bpm/240)) - end - gc_setAlpha(1) - FONT.set(65) - gc_print(bpmString, 835 - (GAME.ecloseCard and 20 or 0), 100 + dy) - else - local speedString = "SPEED: "..tostring(MATH.floor(speedMod*100)/100) .. "x" - gc_setColor(bgmColors[BgmPlaying] or clr.LT) - if BgmPlaying == 'tera' or BgmPlaying == 'terar' or BgmPlaying == 'terae' or BgmPlaying == 'teral' or BgmPlaying == 'terael' then - gc_setColor(COLOR.rainbow_light(2.6 * t * bpm/240)) - end - gc_setAlpha(1) - FONT.set(65) - gc_print(speedString, 835 - (GAME.ecloseCard and 20 or 0), 100 + dy) - end - if countPiecesActive() > 1 then - gc_setColor(COLOR.R) - gc_setAlpha(1) - FONT.set(50) - gc_print("MULTIPLE PIECES!!!", 770 - (GAME.ecloseCard and 20 or 0), baseY + 338 + dy) - GAME.refreshCurrentCombo() - else - GAME.multiplePiecesActive = false - GAME.refreshCurrentCombo() - end - if URM then - gc_replaceTransform(SCR.origin) - gc_setColor(.42, 0, 0, .35) - gc_draw(TEXTURE.pixel, 0, 0, 0, SCR.w, SCR.h) - gc_setColor(0, 0, 0, GAME.mod.EX == 2 and .62 or .42) - gc_draw(TEXTURE.darkCorner, 0, 0, 0, SCR.w / 128, SCR.h / 128) - end -end - -scene.widgetList = { - - -- GAMEPLAY OPTIONS - WIDGET.new { -- Game Play - name = 'gameplay', type = 'button', - x = baseX + 220, y = baseY + 60, w = 410, h = 70, - color = clr.T, - sound_hover = 'menutap', - fontSize = 50, text = "GAME PLAY", textColor = clr.LT, - onClick = function() - MusicPlayer = not MusicPlayer - bpmMode = true - refreshWidgets() - IssueAchv('music_man') - end, - }, - -- BPM button is shared with MP options - WIDGET.new { -- Promotion - name = 'promotion', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "PROMOTION GAUGE", - x = baseX + 40, y = baseY + 60 + 80, - disp = function() return STAT.promotion end, - code = function() - local multiple = GAME.multiplePiecesActive - MSG.clear() - STAT.promotion = not STAT.promotion - MSG('dark', "Rank Promotion Gauge: " .. (STAT.promotion and "ON" or "OFF")) - if STAT.stacker and STAT.promotion then - STAT.stacker = false - MSG('dark', "STACKER and PROMOTION GAUGE are MUTUALLY EXCLUSIVE!") - SFX.play('no') - else - SFX.play('social_dm') - end - GAME.multiplePiecesActive = false - SaveStat() - if multiple then GAME.multiplePiecesActive = true end - end, - }, - WIDGET.new { -- Imperial - name = 'imperial', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "IMPERIAL UNITS", - x = baseX + 500, y = baseY + 60 + 240, - disp = function() return STAT.imperial end, - code = function() - local multiple = GAME.multiplePiecesActive - MSG.clear() - STAT.imperial = not STAT.imperial - SFX.play('social_dm') - MSG('dark', "Imperial Units: " .. (STAT.imperial and "ON" or "OFF")) - GAME.multiplePiecesActive = false - SaveStat() - if multiple then GAME.multiplePiecesActive = true end - end, - }, - WIDGET.new { -- Old Transparent Card - name = 'oldTransparentCard', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "OLD TRANSPARENT CARD", - x = baseX + 40, y = baseY + 60 + 160, - disp = function() return STAT.oldTransparentCard end, - code = function() - local multiple = GAME.multiplePiecesActive - MSG.clear() - STAT.oldTransparentCard = not STAT.oldTransparentCard - SFX.play('social_dm') - MSG('dark', "Transparent Card: " .. (STAT.oldTransparentCard and "V1.0/1.1" or "V1.2+")) - GAME.multiplePiecesActive = false - SaveStat() - if multiple then GAME.multiplePiecesActive = true end - end, - }, - WIDGET.new { -- Old Hitbox - name = 'oldHitbox', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "OLD HITBOX", - x = baseX + 500, y = baseY + 60 + 160, - disp = function() return STAT.oldHitbox end, - code = function() - local multiple = GAME.multiplePiecesActive - MSG.clear() - STAT.oldHitbox = not STAT.oldHitbox - MSG('dark', "Force old hitbox: " .. (STAT.oldHitbox and "ON" or "OFF")) - SFX.play(STAT.oldHitbox and 'social_online' or 'social_offline') - GAME.multiplePiecesActive = false - SaveStat() - if multiple then GAME.multiplePiecesActive = true end - end, - }, - WIDGET.new { -- Use Easy Names - name = 'easyName', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "USE EASY NAMES", - x = baseX + 40, y = baseY + 60 + 240, - disp = function() return STAT.easyName end, - code = function() - local multiple = GAME.multiplePiecesActive - MSG.clear() - STAT.easyName = not STAT.easyName - SFX.play('social_dm') - MSG('dark', "Easy Names In-Game: " .. (STAT.easyName and "ON" or "OFF")) - GAME.multiplePiecesActive = false - SaveStat() - if multiple then GAME.multiplePiecesActive = true end - end, - }, - WIDGET.new { -- Stacker - name = 'stacker', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "STACKER MODE", - x = baseX + 500, y = baseY + 60 + 80, - disp = function() return STAT.stacker end, - code = function() - local multiple = GAME.multiplePiecesActive - MSG.clear() - STAT.stacker = not STAT.stacker - MSG('dark', "Stacker Mode: " .. (STAT.stacker and "ON" or "OFF")) - if STAT.stacker and STAT.promotion then - STAT.promotion = false - SFX.play('no') - MSG('dark', "STACKER and PROMOTION GAUGE are MUTUALLY EXCLUSIVE!") - else - SFX.play('social_dm') - end - GAME.multiplePiecesActive = false - SaveStat() - if multiple then GAME.multiplePiecesActive = true end - end, - }, - -- MUSIC PLAYER OPTIONS - WIDGET.new { -- Music Play - name = 'musicplay', type = 'button', - x = baseX + 220, y = baseY + 60, w = 410, h = 70, - color = clr.T, - sound_hover = 'menutap', - fontSize = 50, text = "MUSIC PLAY", textColor = clr.LT, - onClick = function() - MusicPlayer = not MusicPlayer - refreshWidgets() - end, - }, - WIDGET.new { -- BPM/Speed Button - name = 'bpm', type = 'button', - x = baseX + 685, y = baseY + 60, w = 410, h = 70, - color = clr.T, - sound_hover = 'menutap', - fontSize = 50, text = "", textColor = clr.LT, - onClick = function() - bpmMode = not bpmMode - end, - }, - WIDGET.new { -- Prev Track - name = 'prevtrack', type = 'button', - x = baseX + 220, y = baseY + 60 + 80, w = 410, h = 70, - color = clr.T, - sound_hover = 'menutap', - fontSize = 50, text = "PREV TRACK", textColor = clr.LT, - onClick = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if BgmPlaying:count('f') == 1 then - local floor = -1 - if BgmPlaying ~= 'fomg' then - floor = tonumber(BgmPlaying:gsub('[fr]', ''),10) - 1 - if floor == -1 then - PlayBGM('fomg',true) - mode = '' - else - if floor == 0 and scene.widgetList.reverse.disp() then mode = 'f0r' end - if floor == 1 and scene.widgetList.reverse.disp() then mode = 'f1r' end - PlayBGM('f' .. floor .. (scene.widgetList.reverse.disp() and 'r' or ''),true) - end - else - PlayBGM('f10' .. (scene.widgetList.reverse.disp() and 'r' or ''),true) - end - MSG("bright", "Now Playing: " .. BgmPlaying .. ((mode == 'f1r' and floor == 1 or mode == 'f0r' and floor == 0) and 'r' or '')) - else - MSG("dark", "DISABLE TERASPEED FIRST!") - end - RefreshBGM(mode) - end, - }, - WIDGET.new { -- Next Track - name = 'nexttrack', type = 'button', - x = baseX + 685, y = baseY + 60 + 80, w = 410, h = 70, - color = clr.T, - sound_hover = 'menutap', - fontSize = 50, text = "NEXT TRACK", textColor = clr.LT, - onClick = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if BgmPlaying:count('f') == 1 then - local floor = -1 - if BgmPlaying ~= 'fomg' then - floor = tonumber(BgmPlaying:gsub('[fr]', ''),10) + 1 - if floor == 11 then - PlayBGM('fomg',true) - mode = '' - else - if floor == 1 and scene.widgetList.reverse.disp() then mode = 'f1r' end - PlayBGM('f' .. floor .. (scene.widgetList.reverse.disp() and 'r' or ''),true) - end - else - if scene.widgetList.reverse.disp() then mode = 'f0r' end - PlayBGM('f0',true) - end - MSG("bright", "Now Playing: " .. BgmPlaying .. ((mode == 'f1r' and floor == 1 or mode == 'f0r' and floor == 0) and 'r' or '')) - else - MSG("dark", "DISABLE TERASPEED FIRST!") - end - RefreshBGM(mode) - end, - }, - WIDGET.new { -- Teraspeed - name = 'tera', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "TERASPEED", - x = baseX + 40, y = baseY + 60 + 160, - disp = function() return BgmPlaying:count('t') == 1 end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if BgmPlaying:count('t') == 1 then - if scene.widgetList.reverse.disp() then - if lastNonTera == 'f0' then mode = 'f0r' - elseif lastNonTera == 'f1' then mode = 'f1r' - elseif lastNonTera ~= 'fomg' then lastNonTera = lastNonTera .. (lastNonTera:count('r') == 0 and 'r' or '') - end - end - PlayBGM(lastNonTera, true) - MSG("bright", "Now Playing: " .. BgmPlaying .. ((mode == 'f1r' and BgmPlaying == 'f1' or mode == 'f0r' and BgmPlaying == 'f0') and 'r' or '')) - else - lastNonTera = BgmPlaying - if BgmPlaying:count('r') == 1 then - PlayBGM('terar', true) - else - PlayBGM('tera', true) - end - MSG("bright", "Now Playing: " .. BgmPlaying) - end - RefreshBGM(mode) - end, - }, - WIDGET.new { -- Reverse - name = 'reverse', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "REVERSE", - x = baseX + 500, y = baseY + 60 + 160, - disp = function() return (BgmPlaying:count('t') == 0 and BgmPlaying:count('r') == 1) or BgmPlaying:count('r') == 2 or (mode == 'f0r' and BgmPlaying == 'f0' or mode == 'f1r' and BgmPlaying == 'f1') end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if (BgmPlaying:count('t') == 0 and BgmPlaying:count('r') == 1) or BgmPlaying:count('r') == 2 or (mode == 'f0r' and BgmPlaying == 'f0' or mode == 'f1r' and BgmPlaying == 'f1') then - if BgmPlaying == 'terar' then - PlayBGM('tera', true) - else - mode = '' - PlayBGM(BgmPlaying:gsub('r',''), true) - end - MSG("bright", "Now Playing: " .. BgmPlaying) - else - if BgmPlaying:count('t') == 1 then - PlayBGM('terar', true) - elseif BgmPlaying ~= 'fomg' then - if BgmPlaying == 'f0' or BgmPlaying == 'f1' then mode = BgmPlaying .. 'r' end - PlayBGM(BgmPlaying .. (BgmPlaying:count('r') == 0 and 'r' or ''), true) - else - MSG("dark", "CANNOT REVERSE fomg") - end - if BgmPlaying ~= 'fomg' then MSG("bright", "Now Playing: " .. BgmPlaying .. ((mode == 'f1r' and BgmPlaying == 'f1' or mode == 'f0r' and BgmPlaying == 'f0') and 'r' or '')) end - end - RefreshBGM(mode) - end, - }, - WIDGET.new { -- Uneasy - name = 'uneasy', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "UNEASY (TERA & not REV)", - x = baseX + 40, y = baseY + 60 + 240, - disp = function() return BgmPlaying == 'teral' or BgmPlaying == 'terael' end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if BgmPlaying:count('t') == 0 then - MSG("dark", "ENABLE TERASPEED FIRST!") - elseif scene.widgetList.reverse.disp() then - MSG("dark", "DISABLE REVERSE FIRST!") - else - if BgmPlaying == 'tera' then - PlayBGM('teral', force) - elseif BgmPlaying == 'terae' then - PlayBGM('terael', force) - elseif BgmPlaying == 'teral' then - PlayBGM('tera', force) - elseif BgmPlaying == 'terael' then - PlayBGM('terae', force) - end - MSG("bright", "Now Playing: " .. BgmPlaying) - end - RefreshBGM(mode) - end, - }, - WIDGET.new { -- Smithy Mode - name = 'smithyMode', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = clr.T, text = "SMITHY (TERA & not REV)", - x = baseX + 500, y = baseY + 60 + 240, - disp = function() return BgmPlaying == 'terae' or BgmPlaying == 'terael' end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if BgmPlaying:count('t') == 0 then - MSG("dark", "ENABLE TERASPEED FIRST!") - elseif scene.widgetList.reverse.disp() then - MSG("dark", "DISABLE REVERSE FIRST!") - else - if BgmPlaying == 'tera' then - PlayBGM('terae', force) - elseif BgmPlaying == 'terae' then - PlayBGM('tera', force) - elseif BgmPlaying == 'teral' then - PlayBGM('terael', force) - elseif BgmPlaying == 'terael' then - PlayBGM('teral', force) - end - MSG("bright", "Now Playing: " .. BgmPlaying) - end - RefreshBGM(mode) - end, - }, - -- PIECE EFFECTS - WIDGET.new { -- pieces - name = 'pieces', - type = 'text', alignX = 'left', - text = "PIECE EFFECTS", - color = clr.T, - fontSize = 50, - x = baseX + 20, y = baseY + 370, - }, - WIDGET.new { -- ez - name = 'ez', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.lR, text = "eZ - Nightcore+", - x = baseX + 40, y = baseY + 50 + 400, - disp = function() return GAME.enightcore end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if not GAME.enightcore and anyPieceActive() then - SFX.play('damage_alert') - MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") - GAME.multiplePiecesActive = true - else - SFX.play('social_dm') - end - GAME.enightcore = not GAME.enightcore - MSG('dark', "eZ: " .. (GAME.enightcore and "ON" or "OFF")) - RefreshBGM(mode) - end, - }, - WIDGET.new { -- es - name = 'es', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.lG, text = "eS - Slow-mo+", - x = baseX + 500, y = baseY + 50 + 400, - disp = function() return GAME.eslowmo end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if not GAME.eslowmo and anyPieceActive() then - SFX.play('damage_alert') - MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") - GAME.multiplePiecesActive = true - else - SFX.play('social_dm') - end - GAME.eslowmo = not GAME.eslowmo - MSG('dark', "eS: " .. (GAME.eslowmo and "ON" or "OFF")) - RefreshBGM(mode) - end, - }, - WIDGET.new { -- ej - name = 'ej', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.lB, text = "eJ - Glass Card+", - x = baseX + 40, y = baseY + 50 + 480, - disp = function() return GAME.eglassCard end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if not GAME.eglassCard and anyPieceActive() then - SFX.play('damage_alert') - MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") - GAME.multiplePiecesActive = true - else - SFX.play('social_dm') - end - GAME.eglassCard = not GAME.eglassCard - MSG('dark', "eJ: " .. (GAME.eglassCard and "ON" or "OFF")) - refreshWidgets() - RefreshBGM(mode) - end, - }, - WIDGET.new { -- el - name = 'el', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.lO, text = "eL - Slow Leak", - x = baseX + 500, y = baseY + 50 + 480, - disp = function() return GAME.efastLeak end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if not GAME.efastLeak and anyPieceActive() then - SFX.play('damage_alert') - MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") - GAME.multiplePiecesActive = true - else - SFX.play('social_dm') - end - GAME.efastLeak = not GAME.efastLeak - MSG('dark', "eL: " .. (GAME.efastLeak and "ON" or "OFF")) - RefreshBGM(mode) - end, - }, - WIDGET.new { -- eT - name = 'et', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.lM, text = "eT - Transparent UI", - x = baseX + 40, y = baseY + 50 + 560, - disp = function() return GAME.einvisUI end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if not GAME.einvisUI and anyPieceActive() then - SFX.play('damage_alert') - MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") - GAME.multiplePiecesActive = true - else - SFX.play('social_dm') - end - GAME.einvisUI = not GAME.einvisUI - MSG('dark', "eT: " .. (GAME.einvisUI and "ON" or "OFF")) - RefreshBGM(mode) - end, - }, - WIDGET.new { -- eo - name = 'eo', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.lY, text = "eO - Transparent Card", - x = baseX + 500, y = baseY + 50 + 560, - disp = function() return GAME.einvisCard end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if not GAME.einvisCard and anyPieceActive() then - SFX.play('damage_alert') - MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") - GAME.multiplePiecesActive = true - else - SFX.play('social_dm') - end - GAME.einvisCard = not GAME.einvisCard - MSG('dark', "eO: " .. (GAME.einvisCard and "ON" or "OFF")) - RefreshBGM(mode) - end, - }, - WIDGET.new { -- ei - name = 'ei', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.lC, text = "eI - Closer Card", - x = baseX + 40, y = baseY + 50 + 640, - disp = function() return GAME.ecloseCard end, - code = function() - MSG.clear() - TASK.removeTask_code(Task_MusicEnd) - if not GAME.ecloseCard and anyPieceActive() then - SFX.play('damage_alert') - MSG('dark', "WARNING: MULTIPLE PIECES ENABLED DISABLES SCORING AND MAY CAUSE ISSUES. DO NOT REPORT!") - GAME.multiplePiecesActive = true - else - SFX.play('social_dm') - end - GAME.ecloseCard = not GAME.ecloseCard - MSG('dark', "eI: " .. (GAME.ecloseCard and "ON" or "OFF")) - refreshWidgets() - RefreshBGM(mode) - end, - }, - WIDGET.new { -- urm - name = 'urm', type = 'checkBox', - fillColor = clr.cbFill, - frameColor = clr.cbFrame, - textColor = COLOR.R, text = "Ultra Reverse", - x = baseX + 500, y = baseY + 50 + 640, - disp = function() return URM end, - code = function() - URM = not URM - SFX.play(URM and 'exchange' or 'undo') - GAME.hardMode = GAME.mod.EX > 0 or GAME.anyRev and not URM - GAME.refreshLayout() - GAME.refreshUltra() - GAME.refreshCurrentCombo() - GAME.refreshPBText() - RefreshBGM(mode) - GAME.refreshRPC() - RefreshHelpText() - end, - }, - WIDGET.new { -- Clear Button - name = 'clear', type = 'button', - x = baseX + 220, y = baseY + 60 + 720, w = 410, h = 70, - color = clr.T, - sound_hover = 'menutap', - fontSize = 50, text = "CLEAR PIECES", textColor = clr.LT, - onClick = function() - if anyPieceActive() or URM then - SFX.play('allclear') - MSG('dark', 'All Clear') - else - if combo == 0 or (STAT.unlockAll and ACHV.lazy_bastard) then - MSG.clear() - MSG("dark", "What do you want me to deselect?") - SFX.play('no') - elseif combo < 16 then - local str = '' - for i = 1, combo do - str = str .. '?' - end - MSG.clear() - MSG("dark", str) - SFX.play('combo_' .. combo) - else - if not ACHV.lazy_bastard then - IssueAchv('lazy_bastard') - else - MSG("dark", "Fine, okay, everything is unlocked now.") - end - GAME.unlockAll() - SFX.play('combo_16') - end - combo = combo + 1 - comboTimer = 3 - end - URM = false - GAME.nightcore = false - GAME.slowmo = false - GAME.glassCard = false - GAME.fastLeak = false - GAME.invisUI = false - GAME.invisCard = false - GAME.closeCard = false - GAME.enightcore = false - GAME.eslowmo = false - GAME.eglassCard = false - GAME.efastLeak = false - GAME.einvisUI = false - GAME.einvisCard = false - GAME.ecloseCard = false - GAME.multiplePiecesActive = false - PieceSFXID = #PieceData - GAME.hardMode = GAME.mod.EX > 0 or GAME.anyRev and not URM - GAME.refreshLayout() - GAME.refreshUltra() - GAME.refreshCurrentCombo() - GAME.refreshPBText() - RefreshBGM(mode) - GAME.refreshRPC() - RefreshHelpText() - refreshWidgets() - end, - }, - WIDGET.new { -- normal piece button - name = 'help2', type = 'button', - x = baseX + 685, y = baseY + 60 + 720, w = 410, h = 70, - color = clr.T, - sound_hover = 'menutap', - fontSize = 50, text = "CYCLE PIECES", textColor = clr.LT, - onClick = function() - PieceSFXID = (PieceSFXID or 0) % #PieceData + 1 - if PieceSFXID <= #PieceData - 1 then - local piece = ('zsjltoi'):sub(PieceSFXID, PieceSFXID) - SFX.play(piece, 1, 0, Tone(6)) - if PieceSFXID > 7 then - SFX.play('combo_'..(PieceSFXID - 7)..'_power', 1, 0, Tone(0)) - end - else - SFX.play('allclear') - end - - --for i = 1, 7 do - -- Trevor Smithy - for i = 1, #PieceData - 1 do - GAME[PieceData[i].id] = PieceSFXID == i - end - - GAME.refreshLayout() - RefreshBGM() - GAME.refreshRPC() - -- Trevor Smithy - GAME.refreshCurrentCombo() - GAME.multiplePiecesActive = false - MSG({ - cat = 'dark', - str = PieceData[PieceSFXID].popup, - time = 1.2 - }) - end, - }, - WIDGET.new { - name = 'description', type = 'hint', - pos = { 0.777, 1 }, x = 0, y = -25, w = 45, cornerR = 20, - color = clr.L, textColor = clr.L, - fontSize = 40, text = "?", -- Dynamic text - sound_hover = 'menutap', - labelPos = 'left', - floatFontSize = 20, - floatText = MusicPlayer and mpDescriptionTable[descriptionIndex] or descriptionTable[descriptionIndex], -- Dynamic text - onPress = function() - local piece = love.mouse.isDown('2') or love.keyboard.isDown('lctrl', 'rctrl') - descriptionIndex = descriptionIndex + 1 - if descriptionIndex > #descriptionTable then descriptionIndex = 1 end - scene.widgetList.description.floatText = piece and pieceDescriptionTable[descriptionIndex] or MusicPlayer and mpDescriptionTable[descriptionIndex] or descriptionTable[descriptionIndex] - scene.widgetList.description:reset() - end - }, - - WIDGET.new { - name = 'back', type = 'button', - pos = { 0, 0 }, x = 60, y = 140, w = 160, h = 60, - color = { .15, .15, .15 }, - sound_hover = 'menutap', - fontSize = 30, text = " BACK", textColor = 'DL', - onClick = function() love.keypressed('escape') end, - }, -} - -return scene diff --git a/version.lua b/version.lua index 5e5de4c6..15027ac0 100644 --- a/version.lua +++ b/version.lua @@ -1,8 +1,8 @@ return { ["appName"] = "Zenith Clicker: Easy Mode", - ["apkCode"] = 010201, - ["verCode"] = 010201, + ["apkCode"] = 010203, + ["verCode"] = 010203, - ["appVer"] = "eV1.02.01", - ["verStr"] = "1.02.01", + ["appVer"] = "eV1.02.03", + ["verStr"] = "1.02.03", }