diff --git a/NoteSkins/dance/midi-note/metrics.ini b/NoteSkins/dance/midi-note/metrics.ini
index 600751263c..4969099512 100644
--- a/NoteSkins/dance/midi-note/metrics.ini
+++ b/NoteSkins/dance/midi-note/metrics.ini
@@ -8,7 +8,7 @@ TapNoteAnimationLength=4
TapAdditionAnimationLength=4
TapMineAnimationLength=1
TapLiftAnimationLength=4
-HoldHeadAnimationLength=4 // doesn't matter. Only 1 frame anyway.
+HoldHeadAnimationLength=1 // doesn't matter. Only 1 frame anyway.
HoldTopCapAnimationLength=4 // doesn't matter. Only 1 frame anyway.
HoldBottomCapAnimationLength=4 // doesn't matter. Only 1 frame anyway.
HoldBodyAnimationLength=4 // doesn't matter. Only 1 frame anyway.
@@ -35,7 +35,7 @@ TapFakeNoteColorTextureCoordSpacingX=0
TapFakeNoteColorTextureCoordSpacingY=0.125
HoldHeadNoteColorTextureCoordSpacingX=0
-HoldHeadNoteColorTextureCoordSpacingY=0.125
+HoldHeadNoteColorTextureCoordSpacingY=0
[GhostArrowDim]
NoneCommand=
diff --git a/Themes/_themekit-piu/BGAnimations/Screen in.lua b/Themes/_themekit-piu/BGAnimations/Screen in.lua
new file mode 100644
index 0000000000..4ad6ca4625
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/Screen in.lua
@@ -0,0 +1 @@
+return Def.Actor { OnCommand=cmd(sleep,0.3); }
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/Screen out.lua b/Themes/_themekit-piu/BGAnimations/Screen out.lua
new file mode 100644
index 0000000000..4ad6ca4625
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/Screen out.lua
@@ -0,0 +1 @@
+return Def.Actor { OnCommand=cmd(sleep,0.3); }
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenCustomOptionsList overlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenCustomOptionsList overlay/default.lua
new file mode 100644
index 0000000000..ea0e850f1f
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenCustomOptionsList overlay/default.lua
@@ -0,0 +1,384 @@
+local PlayerIndexes = { PlayerNumber_P1 = 1, PlayerNumber_P2 = 1 }
+-- Reads mods from a file
+-- keywords: Speed, Noteskins, None, Clear
+local function ReadMods()
+ local file = THEME:GetCurrentThemeDirectory() .. "mods.txt"
+ local mods = File.Read( file )
+ if not mods
+ or mods == ""
+ then
+ local buff = ";Set mods here, one per line or various in one separated with commas\r\n;Keywords: 'Speed', 'Noteskins', 'None', 'Clear'\r\nSpeeds\r\nNoteskins"
+ File.Write(file,buff)
+ return {
+ ReadSpeedMods();
+ NOTESKIN:GetNoteSkinNames();
+ "Clear";
+ }
+ end
+
+ mods = string.gsub(mods,"\r","")
+ mods = split("\n",mods)
+
+ local ret = {}
+ local clear = false
+
+ for k,v in ipairs(mods) do
+ if string.sub(v,1,1) == ";"
+ or v == ""
+ then
+ --skip
+ elseif v == "Speeds" then
+ table.insert(ret, ReadSpeedMods())
+ elseif v == "Noteskins" then
+ table.insert(ret, NOTESKIN:GetNoteSkinNames())
+ else
+ local ModToAdd = string.gsub(v,"%s","")
+ if string.find(ModToAdd, ",") ~= nil then
+ ModToAdd = split(",", ModToAdd)
+ if ModToAdd[1] ~= "None" then
+ table.insert(ModToAdd,1,"None")
+ end
+ table.insert(ret,ModToAdd)
+ else
+ if ModToAdd == "Clear" then
+ if not clear then table.insert(ret,ModToAdd) end
+ clear = true
+ end
+ end
+ end
+ end
+ -- This will happen...
+ if not clear then table.insert(ret,"Clear") end
+
+ return ret
+end
+
+local modslist = ReadMods()
+
+-- Displays the mods with actorscrollers
+local function OptionsListDisplay(player)
+ local function GetPlayerMods()
+ local playerstate = GAMESTATE:GetPlayerState(player)
+ local playermods = playerstate:GetPlayerOptionsArray('ModsLevel_Preferred')
+ return playermods
+ end
+
+ local make = {}
+ -- iterate modslist entries
+ for k,v in ipairs(modslist) do
+ -- not kinopio
+ local RowToAdd
+ if type(v) == "table" then
+ -- it's a table, make it a scroller
+ local choices = {}
+ -- build the choices
+ for i,j in ipairs(v) do
+ choices[i] = LoadFont()..{ Text=j };
+ end
+ RowToAdd = Def.ActorScroller {
+ NumItemsToDraw=3;
+ SecondsPerItem=0.075;
+ -- init indexes here
+ -- I like how InitCommand is not allowed to be played or queued
+ -- (HURR TOO MUCH COMMANDS ARG!)
+ SetChoicesCommand=function(self)
+ local found = false
+ --SCREENMAN:SystemMessage(join(",", defmods))
+ for idx,Mod in ipairs(GetPlayerMods()) do
+ -- In before I forgot what's this: those are the nod entries
+ for jdx,Nod in ipairs(v) do
+ if Mod == Nod then
+ found = true
+ self:SetCurrentAndDestinationItem(jdx-1);
+ break
+ end
+ end
+ end
+ -- oops, no defaults, set them
+ if not found then
+ for idx,Mod in ipairs(v) do
+ if Mod == "1x"
+ or Mod == "default"
+ or Mod == "None"
+ then
+ self:SetCurrentAndDestinationItem(idx-1);
+ break
+ else
+ self:SetCurrentAndDestinationItem(0);
+ end
+ end
+ end
+ end;
+ CleanModsMessageCommand=function(self,params)
+ if player ~= params.PlayerNumber then return end
+ self:playcommand("SetChoices");
+ end;
+ InitCommand=function(self)
+ self:SetLoop(true);
+ self:playcommand("SetChoices");
+ end;
+ TransformFunction=function(self, offset, itemIndex, numItems)
+ self:x(offset * 100);
+ local focus = math.abs(offset)
+ focus = scale(focus,0,1,1,0.75)
+
+ self:zoom(focus)
+ end;
+ ChoiceSwapMessageCommand=function(self,params)
+ if params.PlayerNumber ~= player then return end
+ if params.Row ~= k then return end
+
+ local index = params.Index
+ --SCREENMAN:SystemMessage(ToEnumShortString(player).." row mods index: "..index);
+ if params.bHasLooped then
+ self:SetCurrentAndDestinationItem(-1)
+ end
+
+ self:SetDestinationItem(index-1)
+ end;
+ -- actors are wrapped here:
+ children = choices;
+ };
+ elseif type(v) == "string" then
+ -- it's not, make single switchable choice
+ RowToAdd = Def.ActorFrame {
+ LoadFont()..{
+ Text=v;
+ -- init highlights here
+ SetChoicesCommand=function(self)
+ local cc = color("#000000")
+ for idx,Mod in ipairs(GetPlayerMods()) do
+ if Mod == v then
+ cc = color("#ffffff")
+ break
+ end
+ end
+ if v == "Clear" then
+ cc = color("#0000ff")
+ end
+ self:diffuse(cc);
+ end;
+ InitCommand=function(self)
+ self:playcommand("SetChoices");
+ end;
+ -- Following commands you'll understand (I've heard that somewhere...)
+ CleanModsMessageCommand=function(self,params)
+ --if v == "Clear" then return end
+ if player ~= params.PlayerNumber then return end
+ self:playcommand("SetChoices");
+ --self:diffuse(color("#000000"));
+ end;
+ -- cmd(diffuse,color("#000000"));
+ ChoiceToggleMessageCommand=function(self,params)
+ if params.PlayerNumber ~= player then return end
+ if params.Row ~= k then return end
+
+ local cc = color("#ffffff")
+ if not params.Activated then
+ cc = color("#000000")
+ end
+
+ --self:visible(params.Activated)
+ -- why the fuck is not coloring itself? oh I think I got it... duh!
+ self:diffuse(cc)
+ end;
+ }
+ }
+ else
+ --table.remove(modslist,k)
+ --Def.Actor { };
+ end
+ make[k] = RowToAdd
+ end
+
+ return Def.ActorFrame {
+ Draw.RoundBox(300,320,50,50,color("1,0,1,0.5"));
+ Draw.RoundBox(300,50,25,25,color("1,0,0,0.5"));
+ Def.ActorScroller {
+ Name="OptionsListScroller";
+ NumItemsToDraw=5;
+ SecondsPerItem=0.075;
+ InitCommand=function(self)
+ self:SetLoop(true);
+ end;
+ TransformFunction=function(self, offset, itemIndex, numItems)
+ self:y(offset * 50);
+ end;
+ children = make;
+ };
+ }
+end
+
+-- Internals
+return Def.ActorFrame {
+ OptionsListDisplay(PLAYER_1)..{
+ Name="OptionsListDisplay"..PLAYER_1;
+ Condition=GAMESTATE:IsHumanPlayer(PLAYER_1);
+ InitCommand=function(self)
+ if #GAMESTATE:GetHumanPlayers() == 1
+ and PREFSMAN:GetPreference("Center1Player")
+ then
+ self:CenterX()
+ else
+ self:FromLeft(160)
+ end
+ self:CenterY();
+ end;
+ };
+ OptionsListDisplay(PLAYER_2)..{
+ Name="OptionsListDisplay"..PLAYER_2;
+ Condition=GAMESTATE:IsHumanPlayer(PLAYER_2);
+ InitCommand=function(self)
+ if #GAMESTATE:GetHumanPlayers() == 1
+ and PREFSMAN:GetPreference("Center1Player")
+ then
+ self:CenterX()
+ else
+ self:FromRight(-160)
+ end
+ self:CenterY();
+ end;
+ };
+ -- Everything here and beyond is pure magic
+ CodeMessageCommand=function(self,params)
+ -- I'm reusing code from CustomCodeDetector
+ local code = params.Name
+ local player = params.PlayerNumber
+ local movement = "none"
+ local modscleared = false
+
+ if not GAMESTATE:IsHumanPlayer(player) then return end;
+
+ if code == "Back" then
+ --SCREENMAN:SystemMessage(ToEnumShortString(player).." closed the oplist")
+ SCREENMAN:GetTopScreen():Cancel();
+ elseif code == "Prev" then
+ PlayerIndexes[player] = PlayerIndexes[player]-1
+ if PlayerIndexes[player] < 1 then
+ PlayerIndexes[player] = #modslist
+ movement = "first"
+ end
+ --SCREENMAN:SystemMessage(ToEnumShortString(player).." index: "..PlayerIndexes[player]);
+ elseif code == "Next" then
+ PlayerIndexes[player] = PlayerIndexes[player]+1
+ if PlayerIndexes[player] > #modslist then
+ PlayerIndexes[player] = 1
+ movement = "last"
+ end
+ --SCREENMAN:SystemMessage(ToEnumShortString(player).." index: "..PlayerIndexes[player]);
+ elseif code == "Toggle" then
+ -- changes will be done here
+ -- get playerstate and playermods
+ local playerstate = GAMESTATE:GetPlayerState(player)
+ local playermods = playerstate:GetPlayerOptionsArray('ModsLevel_Preferred')
+
+ -- let's check in what index we are
+ local ModToAdd = modslist[PlayerIndexes[player]]
+ --the mod is a table, scroll those
+ if type(ModToAdd) == "table" then
+ -- iteration, once again, like in the custom code detector I made :x
+ local index = 1
+ local found = false
+ local looped = false
+ for i,j in ipairs(playermods) do
+ for k,l in ipairs(ModToAdd) do
+ if j == l then
+ found = true
+ index = k+1
+ if index > #ModToAdd then
+ index = 1
+ looped = true
+ end
+ --replace
+ playermods[i] = ModToAdd[index]
+ break
+ end
+ end
+ end
+ -- looks like nothing was found, we can assume those are the default mods
+ -- (1x and default noteskin) they are not listed for some reason...
+ if not found then
+ -- set the first on the list (nono, better list 1x and default)
+ for k,v in ipairs(ModToAdd) do
+ if v == "1x"
+ or v == "default"
+ then
+ index = k+1
+ if index > #ModToAdd then
+ index = 1
+ looped = true
+ end
+ table.insert(playermods, ModToAdd[index])
+ break
+ elseif v == "None" then
+ table.insert(playermods, ModToAdd[2])
+ index = 2
+ end
+ end
+ end
+ -- send message broadcasts to be able to move things on the oplist displays
+ MESSAGEMAN:Broadcast("ChoiceSwap",{ Row = PlayerIndexes[player]; Index = index; PlayerNumber = player; bHasLooped = looped })
+ elseif ModToAdd == "Clear" then
+ local defaultmods = PREFSMAN:GetPreference("DefaultModifiers")
+ playermods = split(",", defaultmods)
+ modscleared = true
+ --MESSAGEMAN:Broadcast("CleanMods",{ PlayerNumber = player });
+ else
+ -- if type(ModToAdd) == "string" then end
+ -- we know it's a string...
+ local found = false
+ for i,j in ipairs(playermods) do
+ if j == ModToAdd then
+ -- remove it
+ found = true
+ table.remove(playermods, i)
+ break
+ end
+ end
+
+ if not found then
+ table.insert(playermods, ModToAdd)
+ end
+ MESSAGEMAN:Broadcast("ChoiceToggle",{ Row = PlayerIndexes[player]; Activated = not found; PlayerNumber = player })
+ end
+ -- let's check if noteskins aren't missing (we're avoiding crashes here...)
+ local found = false
+ -- iterate again uh
+ for i,j in ipairs(playermods) do
+ -- yes because noteskins are stored in the second slot...
+ for k,l in ipairs(modslist[2]) do
+ if j == l then
+ found = true
+ break
+ end
+ end
+ end
+ -- apparently there aren't any noteskins...
+ if not found then
+ table.insert(playermods, "default")
+ end
+
+ -- everything is ready to be set
+ playermods = join(", ",playermods)
+ playerstate:SetPlayerOptions('ModsLevel_Preferred',playermods)
+ -- and thats pretty much it :D
+ end
+
+ if modscleared then
+ MESSAGEMAN:Broadcast("CleanMods",{ PlayerNumber = player });
+ end
+
+ --this moves the scroller...
+ local scroller = self:GetChild("OptionsListDisplay"..player):GetChild("OptionsListScroller")
+ if movement ~= "none" then
+ local tomove
+ if movement == "first" then
+ tomove = PlayerIndexes[player]
+ elseif movement == "last" then
+ tomove = PlayerIndexes[player]-2
+ end
+ scroller:SetCurrentAndDestinationItem(tomove);
+ end
+ scroller:SetDestinationItem(PlayerIndexes[player]-1);
+ end;
+};
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenEvaluationNormal overlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenEvaluationNormal overlay/default.lua
new file mode 100644
index 0000000000..6923846a64
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenEvaluationNormal overlay/default.lua
@@ -0,0 +1,118 @@
+local function Labels()
+ local captions = {
+ "Perfect",
+ "Great",
+ "Good",
+ "Bad",
+ "Miss",
+ "Combo",
+ "Score",
+ };
+
+ local t = Def.ActorFrame {}
+
+ for idx,k in ipairs(captions) do
+ local _ = idx-1
+ t[#t+1] = LoadFont("_arial black 20px")..{
+ Text=k;
+ InitCommand=cmd(y,_*40;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+ end
+
+ return t
+end
+
+local function Scores(player)
+ if not player or not GAMESTATE:IsPlayerEnabled(player) then return Def.Actor {} end
+
+ local curstats = STATSMAN:GetCurStageStats():GetPlayerStageStats(player)
+
+ local timmings = {
+ {
+ curstats:GetTapNoteScores('TapNoteScore_CheckpointHit'),
+ curstats:GetTapNoteScores('TapNoteScore_W1'),
+ curstats:GetTapNoteScores('TapNoteScore_W2'),
+ },
+ {
+ curstats:GetTapNoteScores('TapNoteScore_W3')
+ },
+ {
+ curstats:GetTapNoteScores('TapNoteScore_W4')
+ },
+ {
+ curstats:GetTapNoteScores('TapNoteScore_W5')
+ },
+ {
+ curstats:GetTapNoteScores('TapNoteScore_CheckpointMiss'),
+ curstats:GetTapNoteScores('TapNoteScore_Miss'),
+ },
+ {
+ curstats:MaxCombo()
+ },
+ {
+ curstats:GetScore()
+ }
+ }
+
+ local t = Def.ActorFrame {}
+
+ for idx,k in ipairs(timmings) do
+ local _ = idx-1
+ local curstats = STATSMAN:GetCurStageStats():GetPlayerStageStats(player)
+ local number = 0
+
+ for i,v in ipairs(k) do
+ number = number + v-- curstats:GetTapNoteScores(v);
+ end
+
+ t[#t+1] = LoadFont("_arial black 20px")..{
+ Text=string.format("%03d", number); --curstats:GetTapNoteScores(k)
+ InitCommand=cmd(y,_*40;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+ end
+
+ return t
+end
+
+local function Grade(player)
+ if not player or not GAMESTATE:IsPlayerEnabled(player) then return Def.Actor {} end
+
+ local captions = {
+ Grade_Tier01 = "S";
+ Grade_Tier02 = "S";
+ Grade_Tier03 = "A";
+ Grade_Tier04 = "B";
+ Grade_Tier05 = "C";
+ Grade_Tier06 = "D";
+ Grade_Tier07 = "F";
+ Grade_Failed = "S";
+ }
+ local grade = STATSMAN:GetCurStageStats():GetPlayerStageStats(player):GetGrade()
+
+ return LoadFont("_impact 50px")..{
+ Text=captions[grade];
+ --OnCommand=cmd(zoom,2;diffuse,color("#000000");Stroke,color("#ffffff");diffusealpha,0;sleep,1;linear,1;zoom,1;diffuse,color("#000000");Stroke,color("#ffffff");;diffusealpha,1);
+ }
+end
+
+return Def.ActorFrame {
+ LoadFont("_impact 50px")..{
+ Text="Evaluation";
+ InitCommand=cmd(CenterX;y,50;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+ Labels()..{
+ InitCommand=cmd(CenterX;FromTop,130);
+ };
+ Scores(PLAYER_1)..{
+ InitCommand=cmd(FromCenterX,-160;FromTop,130);
+ };
+ Scores(PLAYER_2)..{
+ InitCommand=cmd(FromCenterX,160;FromTop,130);
+ };
+ Grade(PLAYER_1)..{
+ InitCommand=cmd(FromLeft,50;FromTop,240);
+ };
+ Grade(PLAYER_2)..{
+ InitCommand=cmd(FromRight,-50;FromTop,240);
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenGameOver underlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenGameOver underlay/default.lua
new file mode 100644
index 0000000000..5809d099a1
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenGameOver underlay/default.lua
@@ -0,0 +1,6 @@
+return Def.ActorFrame {
+ LoadFont("_impact 50px")..{
+ Text="THE GAME IS OVER";
+ InitCommand=cmd(Center;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenGameplay out.lua b/Themes/_themekit-piu/BGAnimations/ScreenGameplay out.lua
new file mode 100644
index 0000000000..405cbf7623
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenGameplay out.lua
@@ -0,0 +1 @@
+return Def.Actor { OnCommand=cmd(sleep,1); }
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenGameplay overlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenGameplay overlay/default.lua
new file mode 100644
index 0000000000..9894b80cb7
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenGameplay overlay/default.lua
@@ -0,0 +1,30 @@
+--a simple life display...
+local function LifeDisplay(pn)
+ local function update(self)
+ --local this = self:GetChildren()
+ local lifemeter = SCREENMAN:GetTopScreen():GetLifeMeter(pn)
+ --v
+ local life = lifemeter:GetLife()
+ life = clamp(life,0,1)
+
+ self:GetChild("LifeText"):settextf("Life: %.2f%%", life*100)
+ end
+
+ return Def.ActorFrame {
+ InitCommand=cmd(player,pn;SetUpdateFunction,update);
+
+ LoadFont("_arial black 20px")..{
+ --Text="100%";
+ Name="LifeText";
+ };
+ };
+end
+
+return Def.ActorFrame {
+ LoadFont("_impact 50px")..{
+ InitCommand=cmd(CenterX;FromTop,30);
+ Text=string.format("%02i", STATSMAN:GetStagesPlayed()+1);
+ };
+ LifeDisplay(PLAYER_1)..{ InitCommand=cmd(FromCenterX,-160;FromTop,20); };
+ LifeDisplay(PLAYER_2)..{ InitCommand=cmd(FromCenterX,160;FromTop,20); };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenGameplay underlay.lua b/Themes/_themekit-piu/BGAnimations/ScreenGameplay underlay.lua
new file mode 100644
index 0000000000..d5533e3a4e
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenGameplay underlay.lua
@@ -0,0 +1,115 @@
+-- CH32 asked me if this was possible, and as you can see, it is!!
+local function GetSpeedChanges()
+ local smfile = GAMESTATE:GetCurrentSong():GetSongFilePath()
+ local file = File.Read( smfile )
+ if not file then return end
+ -- search the tag
+ local find = string.find(file , "#SPEED:")
+ if not find then return end
+ -- search the next semicolon
+ local last = string.find(file , ";" , find)
+ local found = string.sub(file,find,last)
+ -- cleans
+ found = string.gsub(found, "\r", "")
+ found = string.gsub(found, "\n", "")
+ found = string.gsub(found, "#SPEED:", "")
+ found = string.gsub(found, ";", "")
+ -- make it a table
+ found = split(",", found)
+ -- return it
+ return found
+end
+
+local speeds = GetSpeedChanges()
+
+-- what are those things made of?
+local function update(self)
+ if speeds ~= nil then
+ for idx,Spd in ipairs(speeds) do
+ local part = split("=", Spd)
+ local ebeat = tonumber(part[1]) --WHERE
+ assert(ebeat)
+ local songbeat = GAMESTATE:GetSongBeat()
+
+ if songbeat >= ebeat
+ -- 1/20 beat
+ and songbeat <= ebeat + (1/20)
+ --and not GAMESTATE:GetSongFreeze()
+ --and not GAMESTATE:GetSongDelay()
+ then
+ local bps = 60 / GAMESTATE:GetCurrentSong():GetTimingData():GetBPMAtBeat( ebeat )
+ --local bps = GAMESTATE:GetSongBPS()
+ local value = tonumber(part[2]) --SPEED
+ local approach = part[3] --APPLY TIME
+ -- Odd, it needs to be a string to be evaluated o_o;
+ if not approach then approach = tostring(4*bps) end
+
+ if string.sub(approach,approach:len()) == "s" then
+ approach = string.sub(approach,1,approach:len()-1)
+ approach = tonumber(approach)
+ approach = 1/approach
+ else
+ approach = 1/(approach*bps)
+ end
+
+ local pastspeed = 1
+ if idx > 1 then
+ pastspeed = split("=", speeds[idx-1])
+ pastspeed = tonumber(pastspeed[2])
+ end
+
+ approach = approach * math.abs(value-pastspeed)
+
+ approach = approach + 0.05
+
+ --if value ~= 0 then
+ --approach = value/approach
+ --approach = scale(value,0,approach,0,1)
+ --end
+
+ MESSAGEMAN:Broadcast("SpeedModLaunched",{ Value = value ; Approach = approach });
+ --SCREENMAN:SystemMessage("APP: " .. approach .. " SPD: " .. value);
+ return
+ end
+ end
+ end
+end
+
+return Def.ActorFrame {
+ InitCommand=cmd(SetUpdateFunction,update);
+ SpeedModLaunchedMessageCommand=function(self,params)
+ local approach = params.Approach
+ local value = params.Value
+
+ local playerstate = GAMESTATE:GetPlayerState(PLAYER_1)
+ local playermods = playerstate:GetPlayerOptionsArray('ModsLevel_Preferred')
+
+ local found = false
+ for idx,Mod in ipairs(playermods) do
+ if string.find(Mod,"%dx") ~= nil
+ --or string.find(Mod,"%d.%dx") ~= nil
+ then
+ found = true
+ local xmod = playermods[idx]
+ xmod = string.gsub(xmod,"x","")
+ xmod = tonumber(xmod)
+ xmod = xmod * value
+ --duh, floats
+ xmod = string.format("*%.2f %.2fx",approach,xmod)
+ playermods[idx] = xmod
+ --SCREENMAN:SystemMessage(xmod)
+ end
+ end
+ if not found then
+ local xmod = string.format("*%.2f %.2fx",approach,value)
+ table.insert( playermods, xmod)
+ end
+
+ playermods = join(",",playermods)
+ playerstate:SetPlayerOptions('ModsLevel_Song', playermods)
+ --self:GetChild("_debug"):settext(playermods)
+ --SCREENMAN:SystemMessage(playerstate:GetPlayerOptions('ModsLevel_Preferred'));
+ --SCREENMAN:SystemMessage(value)
+ end;
+ --LoadFont()..{ Name="_debug"; InitCommand=cmd(x,50;CenterY;rotationz,90); };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenNextStage underlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenNextStage underlay/default.lua
new file mode 100644
index 0000000000..221d2bdc75
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenNextStage underlay/default.lua
@@ -0,0 +1,6 @@
+return Def.ActorFrame {
+ LoadFont("_impact 50px")..{
+ Text="Try next stage";
+ InitCommand=cmd(Center;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenProfileLoad overlay.lua b/Themes/_themekit-piu/BGAnimations/ScreenProfileLoad overlay.lua
new file mode 100644
index 0000000000..7315ae6c1d
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenProfileLoad overlay.lua
@@ -0,0 +1,21 @@
+return Def.ActorFrame {
+ BeginCommand=function(self)
+ self:visible(false);
+ if SCREENMAN:GetTopScreen():HaveProfileToLoad() then
+ self:visible(true);
+ self:sleep(1);
+ end;
+ self:queuecommand("Load");
+ end;
+ LoadCommand=function(self)
+ SCREENMAN:GetTopScreen():Continue();
+ end;
+ --
+ Draw.Box(SCREEN_WIDTH,50)..{
+ InitCommand=cmd(Center);
+ };
+ LoadFont("_arial black 20px")..{
+ Text="Loading Profiles...";
+ InitCommand=cmd(Center;skewx,-0.1;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenProfileSave overlay.lua b/Themes/_themekit-piu/BGAnimations/ScreenProfileSave overlay.lua
new file mode 100644
index 0000000000..f59fc1109b
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenProfileSave overlay.lua
@@ -0,0 +1,21 @@
+return Def.ActorFrame {
+ BeginCommand=function(self)
+ self:visible(false);
+ if SCREENMAN:GetTopScreen():HaveProfileToSave() then
+ self:visible(true);
+ self:sleep(1);
+ end;
+ self:queuecommand("Save");
+ end;
+ SaveCommand=function(self)
+ SCREENMAN:GetTopScreen():Continue();
+ end;
+ --
+ Draw.Box(SCREEN_WIDTH,50)..{
+ InitCommand=cmd(Center);
+ };
+ LoadFont("_arial black 20px")..{
+ Text="Saving Profiles...";
+ InitCommand=cmd(Center;skewx,-0.1;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic overlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic overlay/default.lua
new file mode 100644
index 0000000000..fbd5ebfc89
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic overlay/default.lua
@@ -0,0 +1,224 @@
+--Whew... this one took some time...
+local function ModIcons(p)
+ local oldmods
+
+ --todo: add more
+ local noteskinbuttons = {
+ pump = "UpLeft";
+ dance ="Down";
+ };
+ local function ModiconRow(caption)
+ return Def.ActorFrame {
+ Draw.RoundBox(35,35,6,6,color("#32ff00"));
+ Draw.RoundBox(25,25,3,3,color("#32c800"));
+ LoadFont("_arial black")..{
+ Name="caption";
+ Text=caption or "";
+ };
+ LoadActor("i can flash")..{
+ Name="sfx";
+ InitCommand=cmd(blend,Blend.Add;zoom,0.125);
+ SFXCommand=cmd(stoptweening;diffusealpha,1;zoom,0.5;linear,0.2;zoom,1;diffusealpha,0);
+ };
+ }
+ end
+ --ActorScrollers <3
+ return Def.ActorScroller {
+ --TransformFunctions are both love and hate...
+ TransformFunction=function(self, offset, itemIndex, numItems)
+ self:y(offset * 40);
+ end;
+ InitCommand=function(self)
+ local items = self:GetNumChildren()
+ self:SetCurrentAndDestinationItem(items/2);
+ if SSC then
+ self:SetNumItemsToDraw(items);
+ end
+ self:SetLoop(true);
+ self:playcommand("Set");
+ end;
+ PlayerOptionsChangedMessageCommand=cmd(playcommand,"Set");
+ PlayerJoinedMessageCommand=cmd(playcommand,"Set");
+ --Here's where the magic happens
+ SetCommand=function(self)
+ local playermods = GAMESTATE:GetPlayerState(p):GetPlayerOptionsArray('ModsLevel_Preferred')
+ --clean (invisible everything)
+ for k,v in pairs(self:GetChildren()) do
+ self:GetChild(k):visible(false);
+ end
+ --stop early
+ if not GAMESTATE:IsHumanPlayer(p) then return end;
+ --this thing is based on iteration... ugh
+ for k,v in ipairs(playermods) do
+ --check if it's speed
+ if string.find(v,"%dx") ~= nil then
+ local c = self:GetChild("%dx")
+ c:visible(true);
+ c:GetChild("caption"):settext(v);
+ c:GetChild("sfx"):playcommand("SFX");
+ else
+ --check if it's noteskin
+ local noteskins = NOTESKIN:GetNoteSkinNames()
+ for i,n in ipairs(noteskins) do
+ if n == v then
+ local c = self:GetChild("Noteskin")
+ local button = noteskinbuttons[sGame] or "fallback"
+ local toload = NOTESKIN:GetPathForNoteSkin(button, "Tap Note", v)
+ --make it visible
+ c:visible(true);
+ --adjust sizes here
+ c:GetChild("skingraphic"):Load(toload);
+ c:GetChild("skingraphic"):zoom(0.45);
+ --effects
+ c:GetChild("skinframe"):GetChild("sfx"):playcommand("SFX");
+ else
+ --it's anything else then
+ local c = self:GetChild(v)
+ if c then
+ c:visible(true);
+ c:GetChild("sfx"):playcommand("SFX");
+ end
+ end
+ end
+ end
+ --yeah whatever...
+ self:GetChild("revg"):visible(getenv("GradeReverse"..p));
+ self:GetChild("revg"):GetChild("sfx"):playcommand("SFX");
+ end
+
+ oldmods = playermods
+ end;
+ --speed
+ ModiconRow("1x")..{ Name="%dx" };
+ --reserved for noteskins
+ Def.ActorFrame {
+ Name="Noteskin";
+ ModiconRow("")..{ Name="skinframe"; };
+ Def.Sprite { Name="skingraphic"; };
+ };
+ --the rest
+ ModiconRow("RS")..{ Name="SuperShuffle" };
+ ModiconRow("MR")..{ Name="Left" };
+ ModiconRow("VN")..{ Name="Hidden" };
+ ModiconRow("FD")..{ Name="Dark" };
+ ModiconRow("XM")..{ Name="XMode" };
+ ModiconRow("RG")..{ Name="revg" };
+ }
+end
+
+local function DifficultyMeter(p)
+ return LoadFont("_impact 50px")..{
+ Text="";
+ SetCommand=function(self)
+ if not GAMESTATE:IsHumanPlayer(p) then return end;
+
+ local steps = GAMESTATE:GetCurrentSteps(p)
+ local diff = steps:GetDifficulty()
+ local stype = steps:GetStepsType()
+ local desc = steps:GetDescription()
+ local meter = steps:GetMeter()
+ --local autogen = steps:IsAutogen() and "AUTO " or ""
+
+ --compatible
+ local text = DifficultyAndStepstypeToString(diff,stype,desc)
+ text = string.upper(text);
+
+ self:settextf("%s [%d]",text,meter);
+ end;
+ CurrentSongChangedMessageCommand=function(self)
+ local song = GAMESTATE:GetCurrentSong()
+ if not song then self:visible(false); return end
+ self:visible(true);
+ end;
+ };
+end
+
+local function SongInformationDisplay()
+ local index = 1
+ return LoadFont("_arial black 20px")..{
+ --Text="asd";
+ SetCommand=function(self)
+ local song = GAMESTATE:GetCurrentSong()
+ if not song then self:diffusealpha(0); return end
+
+ local title = song:GetDisplayFullTitle();
+ local artist = song:GetDisplayArtist();
+ local bpm = song:GetDisplayBpms() --GetTimmingData():GetActualBPM()
+ local group = song:GetGroupName();
+ local length = song:MusicLengthSeconds();
+ if length == 150 then
+ length = "Lengthless"
+ else
+ local longmara
+ if song:IsLong() then
+ longmara = " Long song"
+ elseif song:IsMarathon() then
+ longmara = " Marathon song"
+ else
+ longmara = ""
+ end
+ length = string.format("%02d:%02d%s",length/60,length%60,longmara)
+ end
+
+ if bpm[1] == bpm[2] then
+ bpm = string.format("BPM %d", bpm[1])
+ else
+ bpm = string.format("BPM %d - %d",bpm[1],bpm[2])
+ end
+
+ local metadata = {title,artist,bpm,group,length}
+
+ local toset = metadata[index]
+
+ index = index+1
+ if index > #metadata then index = 1 end
+
+ --self:finishtweening();
+ self:settext(toset);
+ self:linear(0.2);
+ self:diffusealpha(1);
+ self:sleep(1);
+ self:linear(0.2)
+ self:diffusealpha(0);
+ self:queuecommand("Set");
+ end;
+ CurrentSongChangedMessageCommand=function(self)
+ --reset index
+ index = 1
+ --start looping
+ self:stoptweening();
+ self:linear(0.2)
+ self:diffusealpha(0);
+ self:queuecommand("Set")
+ end;
+ OffCommand=cmd(finishtweening);
+ };
+end
+
+return Def.ActorFrame {
+ DifficultyMeter(PLAYER_1)..{
+ InitCommand=cmd(FromCenterX,-120;FromTop,100;zoom,0.75;diffuse,color("#646464");Stroke,color("#ffffff"));
+ CurrentStepsP1ChangedMessageCommand=cmd(playcommand,"Set");
+ };
+ DifficultyMeter(PLAYER_2)..{
+ InitCommand=cmd(FromCenterX,120;FromTop,100;zoom,0.75;diffuse,color("#646464");Stroke,color("#ffffff"));
+ CurrentStepsP2ChangedMessageCommand=cmd(playcommand,"Set");
+ };
+ Draw.RoundBox(SCREEN_WIDTH*0.75+10,50,color("#ffffff"))..{
+ InitCommand=cmd(CenterX;FromBottom,-75);
+ };
+ Draw.RoundBox(SCREEN_WIDTH*0.75,40,5,5,color("#0000c8"))..{
+ InitCommand=cmd(CenterX;FromBottom,-75);
+ };
+ SongInformationDisplay()..{
+ InitCommand=cmd(CenterX;FromBottom,-75;diffuse,color("#009600");Stroke,color("#000000"));
+ };
+ ModIcons(PLAYER_1)..{
+ InitCommand=cmd(FromLeft,30;FromTop,240);
+ Condition=not GetUserPrefB("OptionsMode");
+ };
+ ModIcons(PLAYER_2)..{
+ InitCommand=cmd(FromRight,-30;FromTop,240);
+ Condition=not GetUserPrefB("OptionsMode");
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic overlay/i can flash.png b/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic overlay/i can flash.png
new file mode 100644
index 0000000000..9d3f04542c
Binary files /dev/null and b/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic overlay/i can flash.png differ
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic underlay.lua b/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic underlay.lua
new file mode 100644
index 0000000000..d4cbce24e1
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenSelectMusic underlay.lua
@@ -0,0 +1,66 @@
+return Def.ActorFrame {
+ InitCommand=function(self)
+ setenv("GradeReverse" .. PLAYER_1, false)
+ setenv("GradeReverse" .. PLAYER_2, false)
+ --setenv("UnderAttack", false)
+ --setenv("Drop", false)
+ end;
+ CodeMessageCommand=function(self,params)
+ local code = params.Name
+ local player = params.PlayerNumber
+ if not GAMESTATE:IsHumanPlayer(player) then return end;
+
+ if not GetUserPrefB("OptionsMode") then
+ --Yeah
+ if not CustomCodeDetector(code,player,true) then
+ --handling envutils here
+ if code == "GradeReverse"
+ --or code == "any envutil wich requires to be per player"
+ then
+ if not getenv( code..player ) then
+ setenv( code..player, true)
+ else
+ setenv( code..player, false)
+ end
+ else --general envutils (not per player)
+ if not getenv( code ) then
+ setenv( code, true)
+ else
+ setenv( code, false)
+ end
+ end
+ end
+
+ if code == "Cancel" then
+ setenv("GradeReverse"..player,false)
+ end
+
+ MESSAGEMAN:Broadcast("PlayerOptionsChanged", { PlayerNumber = player })
+ --SOUND:PlayOnce(THEME:GetPathS("ScreenSelectMusic","Options"))
+ else
+ if code == "Summon" then
+ --this lua binding is awesome
+ --SCREENMAN:SystemMessage(ToEnumShortString(player).." opened the oplist")
+ self:sleep(0.5);
+ self:queuecommand("OpenCustomOpList");
+ end
+ end
+ end;
+ OpenCustomOpListCommand=function(self) SCREENMAN:AddNewScreenToTop("ScreenCustomOptionsList") end;
+ PlayerOptionsChangedMessageCommand=function(self,params)
+ local player = params.PlayerNumber
+ local playermods = GAMESTATE:GetPlayerState(player):GetPlayerOptions('ModsLevel_Preferred')
+ --SCREENMAN:SystemMessage(ToEnumShortString(player).." mods: "..playermods);
+ end;
+ LoadSound("START")..{
+ OffCommand=cmd(play);
+ };
+ LoadSound("ScreenSelectMusic","Options")..{
+ PlayerOptionsChangedMessageCommand=cmd(stop;play);
+ };
+ LoadSound("3-2")..{
+ --TwoPartConfirmCanceledMessageCommand=cmd(play);
+ SongChosenMessageCommand=cmd(stop;play);
+ OffCommand=cmd(play);
+ };
+}
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenStageBreak underlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenStageBreak underlay/default.lua
new file mode 100644
index 0000000000..134b9a6574
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenStageBreak underlay/default.lua
@@ -0,0 +1,6 @@
+return Def.ActorFrame {
+ LoadFont("_impact 50px")..{
+ Text="Epic fail...";
+ InitCommand=cmd(Center;diffuse,color("#000000");Stroke,color("#ffffff"));
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenStageInformation underlay.lua b/Themes/_themekit-piu/BGAnimations/ScreenStageInformation underlay.lua
new file mode 100644
index 0000000000..b68168c6ee
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenStageInformation underlay.lua
@@ -0,0 +1,24 @@
+local song = GAMESTATE:GetCurrentSong()
+--assert(song,"WHY THIS HAPPENS LOL")
+if not song then
+ song = SONGMAN:GetRandomSong()
+ GAMESTATE:SetCurrentSong( song )
+
+ for k,v in ipairs(PlayerNumber) do
+ local stepsplayer = GAMESTATE:GetCurrentSteps(v)
+ steps = song:GetOneSteps( stepsplayer:GetStepsType() , stepsplayer:GetDifficulty() )
+ GAMESTATE:SetCurrentSteps( steps )
+ end
+end
+
+local path = song:GetBackgroundPath()
+
+SplitMode();
+
+if not path then
+ path = THEME:GetPathG("Common", "fallback background")
+end
+
+return LoadActor(path)..{
+ InitCommand=cmd(scaletocover,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
+};
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenSystemLayer overlay.lua b/Themes/_themekit-piu/BGAnimations/ScreenSystemLayer overlay.lua
new file mode 100644
index 0000000000..5930974b1c
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenSystemLayer overlay.lua
@@ -0,0 +1,79 @@
+local function PlayerName(player)
+ local puns = {
+ --TODO: add moar...
+ ["asd"] = "qwe";
+ ["qwe"] = "asd";
+ };
+
+ return LoadFont("_arial black 20px")..{
+ --Text="PlaceHolder";
+ InitCommand=cmd(zoomx,1);
+ SetCommand=function(self)
+ self:settext("");
+ if PROFILEMAN:IsPersistentProfile(player) then
+ local profile = PROFILEMAN:GetProfile(player)
+ local name = profile:GetDisplayName()
+
+ if name == "" then
+ name = string.gsub(player,"Number_P"," ")
+ end
+ --max 20 chars v
+ name = string.sub(name,1,20)
+ --name = puns[name] or name
+
+ self:settext(name)
+ end
+ end;
+ PlayerJoinedMessageCommand=cmd(playcommand,"Set");
+ CoinInsertedMessageCommand=cmd(playcommand,"Set");
+ CoinModeChangedMessageCommand=cmd(playcommand,"Set");
+ ScreenChangedMessageCommand=cmd(playcommand,"Set");
+ StorageDevicesChangedMessageCommand=cmd(playcommand,"Set");
+ };
+end
+
+return Def.ActorFrame {
+ LoadFont("_fixedsys")..{
+ InitCommand=cmd(blend,'BlendMode_Add'xy,10,5;shadowlength,0;Stroke,{0,0,0,1};wrapwidthpixels,SCREEN_WIDTH*0.45;maxwidth,SCREEN_WIDTH*0.45;horizalign,left;SetTextureFiltering,false;vertalign,top;zoom,1.5);
+ SystemMessageMessageCommand=function(self,params)
+ self:settext(params.Message);
+ self:finishtweening();
+ self:diffusealpha(1);
+ self:sleep(3);
+ self:diffusealpha(0);
+ end;
+ HideSystemMessageMessageCommand=cmd(finishtweening);
+ };
+
+ LoadFont("_arial black 20px")..{
+ InitCommand=cmd(xy,SCREEN_CENTER_X,SCREEN_HEIGHT-20;zoom,1;shadowlength,0;playcommand,"Text");
+ TextCommand=function(self)
+ if GAMESTATE:GetCoinMode() == 'CoinMode_Pay' then
+ local Coins = GAMESTATE:GetCoins()
+ local CoinForCredit = GAMESTATE:GetCoinsNeededToJoin()
+ local Credits = math.floor(Coins/CoinForCredit)
+ local Remain = Coins % CoinForCredit
+ self:settext(string.format("CREDIT(S) %i[%i/%i]", Credits, Remain, CoinForCredit))
+ elseif GAMESTATE:GetCoinMode() == 'CoinMode_Free' then
+ self:settext("Free Play")
+ else --homemode
+ self:settext("Home Mode");
+ end
+ end;
+ PlayerJoinedMessageCommand=cmd(playcommand,"Text");
+ CoinInsertedMessageCommand=cmd(playcommand,"Text");
+ CoinModeChangedMessageCommand=cmd(playcommand,"Text");
+ ScreenChangedMessageCommand=cmd(playcommand,"Text");
+ };
+
+ ScreenChangedMessageCommand=function(self)
+ self:visible(THEME:GetMetric(SCREENMAN:GetTopScreen():GetName(),"ShowCreditDisplay"));
+ end;
+
+ PlayerName(PLAYER_1)..{
+ InitCommand=cmd(xy,20,SCREEN_HEIGHT-20;horizalign,left);
+ };
+ PlayerName(PLAYER_2)..{
+ InitCommand=cmd(xy,SCREEN_WIDTH-20,SCREEN_HEIGHT-20;horizalign,right);
+ };
+}
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenTitleMenu underlay/default.lua b/Themes/_themekit-piu/BGAnimations/ScreenTitleMenu underlay/default.lua
new file mode 100644
index 0000000000..644f3c5323
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenTitleMenu underlay/default.lua
@@ -0,0 +1,6 @@
+return Def.ActorFrame {
+ LoadFont("_arial black 20px")..{
+ Text="Background logo or video must go here...";
+ InitCommand=cmd(CenterX;y,200;Stroke,color("#000000"));
+ };
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenWithMenuElements background.lua b/Themes/_themekit-piu/BGAnimations/ScreenWithMenuElements background.lua
new file mode 100644
index 0000000000..e472028917
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/ScreenWithMenuElements background.lua
@@ -0,0 +1,22 @@
+local particles = {
+ Def.Quad { InitCommand=cmd(FullScreen;diffuse,color("#003200");diffusetopedge,color("#000000")); }
+}
+
+for i=1,30 do
+ particles[#particles+1] = Draw.Oval(math.random(20,80))..{
+ InitCommand=function(self)
+ self:finishtweening();
+ self:decelerate(0.25);
+
+ self:x(math.random(20,SCREEN_WIDTH-20));
+ self:y(math.random(20,SCREEN_HEIGHT-20));
+
+ self:diffuse(math.random(0.2,1),math.random(0.2,1),math.random(0.2,1),math.random(0.75,0.95))
+ end;
+ ScreenChangedMessageCommand=cmd(playcommand,"Init");
+ }
+end
+
+return Def.ActorFrame {
+ children = particles;
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/BGAnimations/_frame 3x1.lua b/Themes/_themekit-piu/BGAnimations/_frame 3x1.lua
new file mode 100644
index 0000000000..aea442644b
--- /dev/null
+++ b/Themes/_themekit-piu/BGAnimations/_frame 3x1.lua
@@ -0,0 +1,13 @@
+--stolen from default theme
+local File, Width = ...
+assert( File );
+assert( Width );
+
+local FullFile = THEME:GetPathB('','_frame files 3x1/'..File )
+local Frame = LoadActor( FullFile )
+
+return Def.ActorFrame {
+ Frame .. { InitCommand=cmd(setstate,0;pause;horizalign,right;x,-Width/2) };
+ Frame .. { InitCommand=cmd(setstate,1;pause;zoomtowidth,Width) };
+ Frame .. { InitCommand=cmd(setstate,2;pause;horizalign,left;x,Width/2) };
+};
diff --git a/Themes/_themekit-piu/Fonts/Common Normal.redir b/Themes/_themekit-piu/Fonts/Common Normal.redir
new file mode 100644
index 0000000000..3307c63107
--- /dev/null
+++ b/Themes/_themekit-piu/Fonts/Common Normal.redir
@@ -0,0 +1 @@
+_arial black 20px
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Fonts/_arial black 20px [alt-stroke] 10x10 (doubleres).png b/Themes/_themekit-piu/Fonts/_arial black 20px [alt-stroke] 10x10 (doubleres).png
new file mode 100644
index 0000000000..659334f4be
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_arial black 20px [alt-stroke] 10x10 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_arial black 20px [alt] 10x10 (doubleres).png b/Themes/_themekit-piu/Fonts/_arial black 20px [alt] 10x10 (doubleres).png
new file mode 100644
index 0000000000..c310d618ff
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_arial black 20px [alt] 10x10 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_arial black 20px [main-stroke] 15x15 (doubleres).png b/Themes/_themekit-piu/Fonts/_arial black 20px [main-stroke] 15x15 (doubleres).png
new file mode 100644
index 0000000000..3787568000
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_arial black 20px [main-stroke] 15x15 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_arial black 20px [main] 15x15 (doubleres).png b/Themes/_themekit-piu/Fonts/_arial black 20px [main] 15x15 (doubleres).png
new file mode 100644
index 0000000000..3411305717
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_arial black 20px [main] 15x15 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_arial black 20px.ini b/Themes/_themekit-piu/Fonts/_arial black 20px.ini
new file mode 100644
index 0000000000..a5e2ae116d
--- /dev/null
+++ b/Themes/_themekit-piu/Fonts/_arial black 20px.ini
@@ -0,0 +1,352 @@
+[common]
+Baseline=25
+Top=11
+LineSpacing=28
+DrawExtraPixelsLeft=1
+DrawExtraPixelsRight=0
+AdvanceExtraPixels=0
+
+[main]
+Line 0= !"#$%&'()*+,-.
+Line 1=/0123456789:;<=
+Line 2=>?@ABCDEFGHIJKL
+Line 3=MNOPQRSTUVWXYZ[
+Line 4=\]^_`abcdefghij
+Line 5=klmnopqrstuvwxy
+Line 6=z{|}~€‚ƒ„…†‡ˆ‰Š
+Line 7=‹ŒŽ‘’“”•–—˜™š›œ
+Line 8=žŸ ¡¢£¤¥¦§¨©ª«¬
+Line 9=®¯°±²³´µ¶·¸¹º»
+Line 10=¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊ
+Line 11=ËÌÍÎÏÐÑÒÓÔÕÖרÙ
+Line 12=ÚÛÜÝÞßàáâãäåæçè
+Line 13=éêëìíîïðñòóôõö÷
+Line 14=øùúûüýþÿ
+
+0=7
+1=7
+2=10
+3=13
+4=13
+5=20
+6=18
+7=6
+8=8
+9=8
+10=11
+11=13
+12=7
+13=7
+14=7
+15=6
+16=13
+17=13
+18=13
+19=13
+20=13
+21=13
+22=13
+23=13
+24=13
+25=13
+26=7
+27=7
+28=13
+29=13
+30=13
+31=12
+32=15
+33=16
+34=16
+35=16
+36=16
+37=14
+38=13
+39=17
+40=17
+41=8
+42=13
+43=17
+44=13
+45=19
+46=17
+47=17
+48=14
+49=17
+50=16
+51=14
+52=14
+53=17
+54=16
+55=20
+56=16
+57=16
+58=14
+59=8
+60=6
+61=8
+62=13
+63=10
+64=7
+65=13
+66=13
+67=13
+68=13
+69=13
+70=8
+71=13
+72=13
+73=7
+74=7
+75=13
+76=7
+77=20
+78=13
+79=13
+80=13
+81=13
+82=9
+83=12
+84=9
+85=13
+86=12
+87=19
+88=13
+89=12
+90=11
+91=8
+92=6
+93=8
+94=13
+95=13
+96=6
+97=13
+98=10
+99=20
+100=13
+101=13
+102=7
+103=20
+104=14
+105=7
+106=20
+107=14
+108=6
+109=6
+110=10
+111=10
+112=10
+113=10
+114=20
+115=7
+116=19
+117=12
+118=7
+119=20
+120=11
+121=16
+122=7
+123=7
+124=13
+125=13
+126=13
+127=13
+128=6
+129=13
+130=7
+131=16
+132=8
+133=13
+134=13
+135=7
+136=16
+137=10
+138=8
+139=13
+140=8
+141=8
+142=7
+143=13
+144=17
+145=7
+146=7
+147=8
+148=8
+149=13
+150=20
+151=20
+152=20
+153=12
+154=16
+155=16
+156=16
+157=16
+158=16
+159=16
+160=20
+161=16
+162=14
+163=14
+164=14
+165=14
+166=8
+167=8
+168=8
+169=8
+170=16
+171=17
+172=17
+173=17
+174=17
+175=17
+176=17
+177=13
+178=17
+179=17
+180=17
+181=17
+182=17
+183=16
+184=14
+185=13
+186=13
+187=13
+188=13
+189=13
+190=13
+191=13
+192=20
+193=13
+194=13
+195=13
+196=13
+197=13
+198=7
+199=7
+200=7
+201=7
+202=13
+203=13
+204=13
+205=13
+206=13
+207=13
+208=13
+209=13
+210=13
+211=13
+212=13
+213=13
+214=13
+215=12
+216=13
+217=12
+
+[alt]
+Line 0= Ą˘Ł¤ĽŚ§¨Š
+Line 1=ŞŤŹŽŻ°ą˛ł
+Line 2=´ľśˇ¸šşťź˝
+Line 3=žżŔÁÂĂÄĹĆÇ
+Line 4=ČÉĘËĚÍÎĎĐŃ
+Line 5=ŇÓÔŐÖ×ŘŮÚŰ
+Line 6=ÜÝŢßŕáâăäĺ
+Line 7=ćçčéęëěíîď
+Line 8=đńňóôőö÷řů
+Line 9=úűüýţ˙
+
+0=7
+1=16
+2=7
+3=13
+4=13
+5=13
+6=14
+7=13
+8=7
+9=14
+10=14
+11=14
+12=14
+13=7
+14=14
+15=14
+16=8
+17=13
+18=7
+19=7
+20=7
+21=10
+22=12
+23=7
+24=7
+25=12
+26=12
+27=13
+28=11
+29=7
+30=11
+31=11
+32=16
+33=16
+34=16
+35=16
+36=16
+37=13
+38=16
+39=16
+40=16
+41=14
+42=14
+43=14
+44=14
+45=8
+46=8
+47=16
+48=16
+49=17
+50=17
+51=17
+52=17
+53=17
+54=17
+55=13
+56=16
+57=17
+58=17
+59=17
+60=17
+61=16
+62=14
+63=13
+64=9
+65=13
+66=13
+67=13
+68=13
+69=7
+70=13
+71=13
+72=13
+73=13
+74=13
+75=13
+76=13
+77=7
+78=7
+79=17
+80=13
+81=13
+82=13
+83=13
+84=13
+85=13
+86=13
+87=13
+88=9
+89=13
+90=13
+91=13
+92=13
+93=12
+94=9
+95=7
diff --git a/Themes/_themekit-piu/Fonts/_fixedsys 8px [alt] 10x10 (mipmaps).png b/Themes/_themekit-piu/Fonts/_fixedsys 8px [alt] 10x10 (mipmaps).png
new file mode 100644
index 0000000000..56add39233
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_fixedsys 8px [alt] 10x10 (mipmaps).png differ
diff --git a/Themes/_themekit-piu/Fonts/_fixedsys 8px [main] 15x15 (mipmaps).png b/Themes/_themekit-piu/Fonts/_fixedsys 8px [main] 15x15 (mipmaps).png
new file mode 100644
index 0000000000..329e3ab85d
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_fixedsys 8px [main] 15x15 (mipmaps).png differ
diff --git a/Themes/_themekit-piu/Fonts/_fixedsys 8px.ini b/Themes/_themekit-piu/Fonts/_fixedsys 8px.ini
new file mode 100644
index 0000000000..4f66a87c4c
--- /dev/null
+++ b/Themes/_themekit-piu/Fonts/_fixedsys 8px.ini
@@ -0,0 +1,352 @@
+[common]
+Baseline=13
+Top=4
+LineSpacing=15
+DrawExtraPixelsLeft=0
+DrawExtraPixelsRight=0
+AdvanceExtraPixels=0
+
+[main]
+Line 0= !"#$%&'()*+,-.
+Line 1=/0123456789:;<=
+Line 2=>?@ABCDEFGHIJKL
+Line 3=MNOPQRSTUVWXYZ[
+Line 4=\]^_`abcdefghij
+Line 5=klmnopqrstuvwxy
+Line 6=z{|}~€‚ƒ„…†‡ˆ‰Š
+Line 7=‹ŒŽ‘’“”•–—˜™š›œ
+Line 8=žŸ ¡¢£¤¥¦§¨©ª«¬
+Line 9=®¯°±²³´µ¶·¸¹º»
+Line 10=¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊ
+Line 11=ËÌÍÎÏÐÑÒÓÔÕÖרÙ
+Line 12=ÚÛÜÝÞßàáâãäåæçè
+Line 13=éêëìíîïðñòóôõö÷
+Line 14=øùúûüýþÿ
+
+0=8
+1=8
+2=8
+3=8
+4=8
+5=8
+6=8
+7=8
+8=8
+9=8
+10=8
+11=8
+12=8
+13=8
+14=8
+15=8
+16=8
+17=8
+18=8
+19=8
+20=8
+21=8
+22=8
+23=8
+24=8
+25=8
+26=8
+27=8
+28=8
+29=8
+30=8
+31=8
+32=8
+33=8
+34=8
+35=8
+36=8
+37=8
+38=8
+39=8
+40=8
+41=8
+42=8
+43=8
+44=8
+45=8
+46=8
+47=8
+48=8
+49=8
+50=8
+51=8
+52=8
+53=8
+54=8
+55=8
+56=8
+57=8
+58=8
+59=8
+60=8
+61=8
+62=8
+63=8
+64=8
+65=8
+66=8
+67=8
+68=8
+69=8
+70=8
+71=8
+72=8
+73=8
+74=8
+75=8
+76=8
+77=8
+78=8
+79=8
+80=8
+81=8
+82=8
+83=8
+84=8
+85=8
+86=8
+87=8
+88=8
+89=8
+90=8
+91=8
+92=8
+93=8
+94=8
+95=8
+96=8
+97=8
+98=8
+99=8
+100=8
+101=8
+102=8
+103=8
+104=8
+105=8
+106=8
+107=8
+108=8
+109=8
+110=8
+111=8
+112=8
+113=8
+114=8
+115=8
+116=8
+117=8
+118=8
+119=8
+120=8
+121=8
+122=8
+123=8
+124=8
+125=8
+126=8
+127=8
+128=8
+129=8
+130=8
+131=8
+132=8
+133=8
+134=8
+135=8
+136=8
+137=8
+138=8
+139=8
+140=8
+141=8
+142=8
+143=8
+144=8
+145=8
+146=8
+147=8
+148=8
+149=8
+150=8
+151=8
+152=8
+153=8
+154=8
+155=8
+156=8
+157=8
+158=8
+159=8
+160=8
+161=8
+162=8
+163=8
+164=8
+165=8
+166=8
+167=8
+168=8
+169=8
+170=8
+171=8
+172=8
+173=8
+174=8
+175=8
+176=8
+177=8
+178=8
+179=8
+180=8
+181=8
+182=8
+183=8
+184=8
+185=8
+186=8
+187=8
+188=8
+189=8
+190=8
+191=8
+192=8
+193=8
+194=8
+195=8
+196=8
+197=8
+198=8
+199=8
+200=8
+201=8
+202=8
+203=8
+204=8
+205=8
+206=8
+207=8
+208=8
+209=8
+210=8
+211=8
+212=8
+213=8
+214=8
+215=8
+216=8
+217=8
+
+[alt]
+Line 0= Ą˘Ł¤ĽŚ§¨Š
+Line 1=ŞŤŹŽŻ°ą˛ł
+Line 2=´ľśˇ¸šşťź˝
+Line 3=žżŔÁÂĂÄĹĆÇ
+Line 4=ČÉĘËĚÍÎĎĐŃ
+Line 5=ŇÓÔŐÖ×ŘŮÚŰ
+Line 6=ÜÝŢßŕáâăäĺ
+Line 7=ćçčéęëěíîď
+Line 8=đńňóôőö÷řů
+Line 9=úűüýţ˙
+
+0=8
+1=8
+2=8
+3=8
+4=8
+5=8
+6=8
+7=8
+8=8
+9=8
+10=8
+11=8
+12=8
+13=8
+14=8
+15=8
+16=8
+17=8
+18=8
+19=8
+20=8
+21=8
+22=8
+23=8
+24=8
+25=8
+26=8
+27=8
+28=8
+29=8
+30=8
+31=8
+32=8
+33=8
+34=8
+35=8
+36=8
+37=8
+38=8
+39=8
+40=8
+41=8
+42=8
+43=8
+44=8
+45=8
+46=8
+47=8
+48=8
+49=8
+50=8
+51=8
+52=8
+53=8
+54=8
+55=8
+56=8
+57=8
+58=8
+59=8
+60=8
+61=8
+62=8
+63=8
+64=8
+65=8
+66=8
+67=8
+68=8
+69=8
+70=8
+71=8
+72=8
+73=8
+74=8
+75=8
+76=8
+77=8
+78=8
+79=8
+80=8
+81=8
+82=8
+83=8
+84=8
+85=8
+86=8
+87=8
+88=8
+89=8
+90=8
+91=8
+92=8
+93=8
+94=8
+95=8
diff --git a/Themes/_themekit-piu/Fonts/_impact 50px [alt-stroke] 10x10 (doubleres).png b/Themes/_themekit-piu/Fonts/_impact 50px [alt-stroke] 10x10 (doubleres).png
new file mode 100644
index 0000000000..45d9f2990f
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_impact 50px [alt-stroke] 10x10 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_impact 50px [alt] 10x10 (doubleres).png b/Themes/_themekit-piu/Fonts/_impact 50px [alt] 10x10 (doubleres).png
new file mode 100644
index 0000000000..1f3da6cd9c
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_impact 50px [alt] 10x10 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_impact 50px [main-stroke] 15x15 (doubleres).png b/Themes/_themekit-piu/Fonts/_impact 50px [main-stroke] 15x15 (doubleres).png
new file mode 100644
index 0000000000..33563d4b04
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_impact 50px [main-stroke] 15x15 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_impact 50px [main] 15x15 (doubleres).png b/Themes/_themekit-piu/Fonts/_impact 50px [main] 15x15 (doubleres).png
new file mode 100644
index 0000000000..1d33a28642
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/_impact 50px [main] 15x15 (doubleres).png differ
diff --git a/Themes/_themekit-piu/Fonts/_impact 50px.ini b/Themes/_themekit-piu/Fonts/_impact 50px.ini
new file mode 100644
index 0000000000..a923f584c5
--- /dev/null
+++ b/Themes/_themekit-piu/Fonts/_impact 50px.ini
@@ -0,0 +1,352 @@
+[common]
+Baseline=57
+Top=18
+LineSpacing=50
+DrawExtraPixelsLeft=4
+DrawExtraPixelsRight=4
+AdvanceExtraPixels=0
+
+[main]
+Line 0= !"#$%&'()*+,-.
+Line 1=/0123456789:;<=
+Line 2=>?@ABCDEFGHIJKL
+Line 3=MNOPQRSTUVWXYZ[
+Line 4=\]^_`abcdefghij
+Line 5=klmnopqrstuvwxy
+Line 6=z{|}~€‚ƒ„…†‡ˆ‰Š
+Line 7=‹ŒŽ‘’“”•–—˜™š›œ
+Line 8=žŸ ¡¢£¤¥¦§¨©ª«¬
+Line 9=®¯°±²³´µ¶·¸¹º»
+Line 10=¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊ
+Line 11=ËÌÍÎÏÐÑÒÓÔÕÖרÙ
+Line 12=ÚÛÜÝÞßàáâãäåæçè
+Line 13=éêëìíîïðñòóôõö÷
+Line 14=øùúûüýþÿ
+
+0=9
+1=14
+2=18
+3=31
+4=27
+5=35
+6=29
+7=9
+8=16
+9=16
+10=14
+11=27
+12=8
+13=15
+14=9
+15=20
+16=27
+17=19
+18=25
+19=27
+20=25
+21=27
+22=27
+23=20
+24=27
+25=27
+26=10
+27=10
+28=27
+29=27
+30=27
+31=26
+32=39
+33=25
+34=28
+35=28
+36=28
+37=21
+38=20
+39=28
+40=28
+41=14
+42=17
+43=27
+44=19
+45=36
+46=27
+47=27
+48=25
+49=27
+50=27
+51=26
+52=23
+53=27
+54=25
+55=41
+56=23
+57=24
+58=20
+59=14
+60=20
+61=14
+62=24
+63=28
+64=17
+65=25
+66=26
+67=25
+68=26
+69=26
+70=14
+71=26
+72=26
+73=13
+74=13
+75=24
+76=13
+77=39
+78=26
+79=26
+80=26
+81=26
+82=18
+83=24
+84=15
+85=26
+86=22
+87=32
+88=22
+89=22
+90=18
+91=18
+92=14
+93=18
+94=26
+95=27
+96=8
+97=22
+98=17
+99=28
+100=27
+101=27
+102=17
+103=51
+104=26
+105=10
+106=34
+107=20
+108=8
+109=8
+110=17
+111=17
+112=17
+113=25
+114=50
+115=17
+116=39
+117=24
+118=10
+119=38
+120=18
+121=24
+122=9
+123=14
+124=26
+125=27
+126=27
+127=24
+128=14
+129=24
+130=17
+131=39
+132=16
+133=19
+134=27
+135=15
+136=39
+137=28
+138=17
+139=27
+140=16
+141=16
+142=17
+143=24
+144=29
+145=17
+146=17
+147=12
+148=16
+149=19
+150=31
+151=32
+152=35
+153=26
+154=25
+155=25
+156=25
+157=25
+158=25
+159=25
+160=36
+161=28
+162=21
+163=21
+164=21
+165=21
+166=14
+167=14
+168=14
+169=14
+170=28
+171=27
+172=27
+173=27
+174=27
+175=27
+176=27
+177=27
+178=27
+179=27
+180=27
+181=27
+182=27
+183=24
+184=25
+185=28
+186=25
+187=25
+188=25
+189=25
+190=25
+191=25
+192=38
+193=25
+194=26
+195=26
+196=26
+197=26
+198=13
+199=13
+200=13
+201=13
+202=26
+203=26
+204=26
+205=26
+206=26
+207=26
+208=26
+209=27
+210=26
+211=26
+212=26
+213=26
+214=26
+215=22
+216=26
+217=22
+
+[alt]
+Line 0= Ą˘Ł¤ĽŚ§¨Š
+Line 1=ŞŤŹŽŻ°ą˛ł
+Line 2=´ľśˇ¸šşťź˝
+Line 3=žżŔÁÂĂÄĹĆÇ
+Line 4=ČÉĘËĚÍÎĎĐŃ
+Line 5=ŇÓÔŐÖ×ŘŮÚŰ
+Line 6=ÜÝŢßŕáâăäĺ
+Line 7=ćçčéęëěíîď
+Line 8=đńňóôőö÷řů
+Line 9=úűüýţ˙
+
+0=9
+1=25
+2=17
+3=19
+4=27
+5=22
+6=26
+7=24
+8=17
+9=26
+10=26
+11=23
+12=20
+13=15
+14=20
+15=20
+16=17
+17=25
+18=17
+19=13
+20=17
+21=21
+22=24
+23=17
+24=17
+25=24
+26=24
+27=23
+28=18
+29=17
+30=18
+31=18
+32=27
+33=25
+34=25
+35=25
+36=25
+37=19
+38=28
+39=28
+40=28
+41=21
+42=21
+43=21
+44=21
+45=14
+46=14
+47=28
+48=28
+49=27
+50=27
+51=27
+52=27
+53=27
+54=27
+55=27
+56=27
+57=27
+58=27
+59=27
+60=27
+61=24
+62=23
+63=28
+64=18
+65=25
+66=25
+67=25
+68=25
+69=13
+70=25
+71=25
+72=25
+73=26
+74=26
+75=26
+76=26
+77=13
+78=13
+79=33
+80=26
+81=26
+82=26
+83=26
+84=26
+85=26
+86=26
+87=27
+88=18
+89=26
+90=26
+91=26
+92=26
+93=22
+94=15
+95=17
diff --git a/Themes/_themekit-piu/Fonts/combo 5x2.png b/Themes/_themekit-piu/Fonts/combo 5x2.png
new file mode 100644
index 0000000000..8374cf1270
Binary files /dev/null and b/Themes/_themekit-piu/Fonts/combo 5x2.png differ
diff --git a/Themes/_themekit-piu/Fonts/combo.ini b/Themes/_themekit-piu/Fonts/combo.ini
new file mode 100644
index 0000000000..c53b8a14b7
--- /dev/null
+++ b/Themes/_themekit-piu/Fonts/combo.ini
@@ -0,0 +1,3 @@
+[main]
+line 0=01234
+line 1=56789
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Graphics/Common fallback background.png b/Themes/_themekit-piu/Graphics/Common fallback background.png
new file mode 100644
index 0000000000..c854724502
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/Common fallback background.png differ
diff --git a/Themes/_themekit-piu/Graphics/Common fallback banner.png b/Themes/_themekit-piu/Graphics/Common fallback banner.png
new file mode 100644
index 0000000000..d084e5887e
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/Common fallback banner.png differ
diff --git a/Themes/_themekit-piu/Graphics/Common window icon.png b/Themes/_themekit-piu/Graphics/Common window icon.png
new file mode 100644
index 0000000000..e07404fc23
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/Common window icon.png differ
diff --git a/Themes/_themekit-piu/Graphics/MusicWheelItem SectionCollapsed NormalPart.redir b/Themes/_themekit-piu/Graphics/MusicWheelItem SectionCollapsed NormalPart.redir
new file mode 100644
index 0000000000..d4bf7f2689
--- /dev/null
+++ b/Themes/_themekit-piu/Graphics/MusicWheelItem SectionCollapsed NormalPart.redir
@@ -0,0 +1 @@
+MusicWheelItem SectionExpanded NormalPart
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Graphics/MusicWheelItem SectionExpanded NormalPart/default.lua b/Themes/_themekit-piu/Graphics/MusicWheelItem SectionExpanded NormalPart/default.lua
new file mode 100644
index 0000000000..92c1eaa8fc
--- /dev/null
+++ b/Themes/_themekit-piu/Graphics/MusicWheelItem SectionExpanded NormalPart/default.lua
@@ -0,0 +1,30 @@
+return Def.ActorFrame {
+ Draw.RoundBox(276,212,20,20,color("#323232"));
+ Draw.RoundBox(256,192,10,10)..{
+ Name="ColorFill";
+ --InitCommand=cmd(zoomto,256,192);
+ SetMessageCommand=function(self,params)
+ local color = {1,1,1,1}
+ if PREFSMAN:GetPreference("MusicWheelUsesSections") ~= 'MusicWheelUsesSections_Never'
+ and GAMESTATE:GetSortOrder() == 'SortOrder_Group'
+ then
+ local goupcolor = SONGMAN:GetSongGroupColor(params.SongGroup)
+
+ if goupcolor ~= nil then
+ color = SONGMAN:GetSongGroupColor(params.SongGroup)
+ end
+ end
+
+ self:diffuse(color);
+ end;
+ };
+
+ LoadFont("_impact 50px")..{
+ Name="GroupName";
+ InitCommand=cmd(shadowlength,0;Stroke,color("#000000");maxwidth,210);
+ SetMessageCommand=function(self,params)
+ text = params.SongGroup
+ self:settext(text);
+ end;
+ };
+}
diff --git a/Themes/_themekit-piu/Graphics/MusicWheelItem Song NormalPart/default.lua b/Themes/_themekit-piu/Graphics/MusicWheelItem Song NormalPart/default.lua
new file mode 100644
index 0000000000..328ebcec58
--- /dev/null
+++ b/Themes/_themekit-piu/Graphics/MusicWheelItem Song NormalPart/default.lua
@@ -0,0 +1,32 @@
+return Def.ActorFrame {
+ Draw.RoundBox(276,212,20,20,color("#323232"));
+ Def.Banner {
+ Name="SongBanner";
+ InitCommand=cmd(scaletoclipped,256,192);
+ SetMessageCommand=function(self,params)
+ local path = params.Song:GetBannerPath()
+ if not path then path = THEME:GetPathG("Common","fallback banner") end
+
+ local bHighResTextures = PREFSMAN:GetPreference("HighResolutionTextures")
+
+ --banner loading stuff...
+ --is on
+ if bHighResTextures == 'HighResolutionTextures_ForceOn' or GetUserPrefB("goodbanners") then
+ self:LoadFromSong(params.Song);
+ --is off
+ elseif bHighResTextures == 'HighResolutionTextures_ForceOff' then
+ self:LoadFromCachedBanner(path);
+ --is auto
+ elseif bHighResTextures == 'HighResolutionTextures_Auto' then
+ local iWidth = DISPLAY:GetDisplayHeight()
+ --display is over ninethousand eh... 480
+ if iWidth > 480 then
+ self:LoadFromSong(params.Song);
+ --display is 480 or less
+ else
+ self:LoadFromCachedBanner(path);
+ end
+ end
+ end;
+ };
+}
diff --git a/Themes/_themekit-piu/Graphics/Player combo.redir b/Themes/_themekit-piu/Graphics/Player combo.redir
new file mode 100644
index 0000000000..04b2ead777
--- /dev/null
+++ b/Themes/_themekit-piu/Graphics/Player combo.redir
@@ -0,0 +1 @@
+_blank
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Graphics/Player judgment/default.lua b/Themes/_themekit-piu/Graphics/Player judgment/default.lua
new file mode 100644
index 0000000000..5f408e976f
--- /dev/null
+++ b/Themes/_themekit-piu/Graphics/Player judgment/default.lua
@@ -0,0 +1,120 @@
+--S, ando usando judge premiere para el themekit Y qu?
+local player = Var "Player"
+-- blah
+--if not getenv then getenv = function() return false end end
+
+--frame correspondiente de cada judgment
+local TNSframe = {
+ TapNoteScore_CheckpointHit = 0;
+ TapNoteScore_W1 = 0;
+ TapNoteScore_W2 = 0;
+ TapNoteScore_W3 = 1;
+ TapNoteScore_W4 = 2;
+ TapNoteScore_W5 = 3;
+ TapNoteScore_Miss = 4;
+ TapNoteScore_CheckpointMiss = 4;
+}
+
+--frames para RG
+local TNSframeReversed = {
+ TapNoteScore_CheckpointHit = 4;
+ TapNoteScore_W1 = 4;
+ TapNoteScore_W2 = 4;
+ TapNoteScore_W3 = 3;
+ TapNoteScore_W4 = 2;
+ TapNoteScore_W5 = 1;
+ TapNoteScore_Miss = 0;
+ TapNoteScore_CheckpointMiss = 0;
+}
+
+return Def.ActorFrame {
+ --init
+ InitCommand=function(self)
+ local this = self:GetChildren()
+ this.judgm:pause();
+
+ --this.judgm:y(-35);
+ --this.combo:y(42);
+
+ this.combo:vertalign(top);
+ this.label:vertalign(top);
+
+ this.judgm:visible(false);
+ this.combo:visible(false);
+ this.label:visible(false);
+
+ --self:runcommandsonleaves(cmd( SetTextureFiltering,false ))
+ end;
+
+ --judges
+ LoadActor("judge")..{
+ Name="judgm";
+ NormalCommand=cmd(shadowlength,0;diffusealpha,1;zoomx,0.913;zoomy,1.175;decelerate,0.175;zoomx,0.62;zoomy,0.78;accelerate,0.06;zoomx,0.63;zoomy,0.82;sleep,0.04;diffusealpha,0.5;zoomx,0.97;zoomy,0.82;sleep,0.04;zoomx,0.63;zoomy,0.82;decelerate,0.175;zoomx,0.82;zoomy,0.82;diffusealpha,0)
+ };
+ --label
+ LoadActor("label")..{
+ Name="label";
+ NormalCommand=cmd(shadowlength,0;diffusealpha,1;zoomx,1.58;zoomy,1.6;y,100;decelerate,0.175;zoomx,1.09;zoomy,1.1;y,70;accelerate,0.06;zoomx,1.14;zoomy,1.1;y,71;sleep,0.04;diffusealpha,0.5;zoomx,1.66;zoomy,1.1;sleep,0.04;zoomx,1.14;zoomy,1.1;decelerate,0.175;zoomx,1.34;zoomy,1.1;diffusealpha,0)
+ };
+ --combo
+ LoadFont("combo")..{
+ Name="combo";
+ NormalCommand=cmd(shadowlength,0;diffusealpha,1;zoomx,1.58;zoomy,1.6;y,30;decelerate,0.175;zoomx,1.09;zoomy,1.1;y,21;accelerate,0.06;zoomx,1.14;zoomy,1.1;y,22;sleep,0.04;diffusealpha,0.5;zoomx,1.66;zoomy,1.1;sleep,0.04;zoomx,1.14;zoomy,1.1;decelerate,0.175;zoomx,1.34;zoomy,1.1;diffusealpha,0)
+ };
+
+ --"PERFECT"!
+ JudgmentMessageCommand=function(self,param)
+ local this = self:GetChildren()
+ local iTns = TNSframe[param.TapNoteScore]
+
+ if getenv("ReverseGrade"..player) then
+ iTns = TNSframeReversed[param.TapNoteScore]
+ end
+
+ --no player, no job
+ if param.Player ~= player then return end
+ if param.HoldNoteScore then return end
+
+ this.judgm:visible(true);
+ this.judgm:setstate(iTns);
+ --this.combo:visible(true);
+ --this.label:visible(true);
+
+ this.judgm:stoptweening();
+ this.judgm:queuecommand("Normal");
+ end;
+
+ ComboCommand=function(self,param)
+ local this = self:GetChildren()
+ local combo = param.Misses or param.Combo;
+
+ --color misses o RG
+ local ccolor
+ if param.Misses then
+ ccolor = color("1,0,0,1");
+ --GradeReverse, combo misses no rojo
+ --puedes cambiar userprefs por getenv
+ if getenv("ReverseGrade"..player) then
+ ccolor = color("1,1,1,1");
+ end
+ else
+ ccolor = color("1,1,1,1");
+ --GradeReverse, combo rojo
+ if getenv("ReverseGrade"..player) then
+ ccolor = color("1,0,0,1");
+ end
+ end;
+
+ --visibilidad
+ this.combo:visible(combo >= 4);
+ this.combo:stoptweening();
+ this.combo:settextf("%03i",combo);
+ this.combo:diffuse(ccolor);
+ this.combo:queuecommand("Normal");
+
+ this.label:visible(combo >= 4);
+ this.label:stoptweening();
+ this.label:diffuse(ccolor);
+ this.label:queuecommand("Normal");
+ end;
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Graphics/Player judgment/judgelabels 1x5.png b/Themes/_themekit-piu/Graphics/Player judgment/judgelabels 1x5.png
new file mode 100644
index 0000000000..28d9252548
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/Player judgment/judgelabels 1x5.png differ
diff --git a/Themes/_themekit-piu/Graphics/Player judgment/label.png b/Themes/_themekit-piu/Graphics/Player judgment/label.png
new file mode 100644
index 0000000000..e4c47cc345
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/Player judgment/label.png differ
diff --git a/Themes/_themekit-piu/Graphics/ScreenMapControllers exit.lua b/Themes/_themekit-piu/Graphics/ScreenMapControllers exit.lua
new file mode 100644
index 0000000000..2f5ca66ae4
--- /dev/null
+++ b/Themes/_themekit-piu/Graphics/ScreenMapControllers exit.lua
@@ -0,0 +1,6 @@
+return LoadFont("Common", "Normal")..{
+ Text="EXIT";
+ InitCommand=cmd(CenterX);
+ GainFocusCommand=cmd(diffuse,color("#FF0000"));
+ LoseFocusCommand=cmd(diffuse,color("#FFFFFF"));
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Graphics/ScreenTitleMenu scroll.lua b/Themes/_themekit-piu/Graphics/ScreenTitleMenu scroll.lua
new file mode 100644
index 0000000000..3dffc70268
--- /dev/null
+++ b/Themes/_themekit-piu/Graphics/ScreenTitleMenu scroll.lua
@@ -0,0 +1,18 @@
+local gc = Var("GameCommand");
+
+return Def.ActorFrame {
+ InitCommand=function(self)
+ local this = self:GetChildren()
+ this.ttf:settext(gc:GetText());
+ this.ttf:Stroke(color("#000000"));
+ this.ttf:diffuse(color("#ffffff"));
+ --this.bkg:zoomto(150,40);
+ --this.bkg:diffuse(color("#c0c0c0"));
+ --this.bkg:fadeleft(0.2);
+ --this.bkg:faderight(0.2);
+ end;
+ --GainFocusCommand=cmd(stoptweening;zoom,1.2);
+ --LoseFocusCommand=cmd(stoptweening;zoom,1.0);
+ --Def.Quad { Name="bkg" };
+ LoadFont("_arial", "black 20px")..{ Name="ttf" };
+};
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Graphics/_Figures/circle.png b/Themes/_themekit-piu/Graphics/_Figures/circle.png
new file mode 100644
index 0000000000..673c22375a
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/_Figures/circle.png differ
diff --git a/Themes/_themekit-piu/Graphics/_Figures/corner.png b/Themes/_themekit-piu/Graphics/_Figures/corner.png
new file mode 100644
index 0000000000..b23468dbcf
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/_Figures/corner.png differ
diff --git a/Themes/_themekit-piu/Graphics/_Figures/triangle.png b/Themes/_themekit-piu/Graphics/_Figures/triangle.png
new file mode 100644
index 0000000000..88565933dd
Binary files /dev/null and b/Themes/_themekit-piu/Graphics/_Figures/triangle.png differ
diff --git a/Themes/_themekit-piu/Languages/en.ini b/Themes/_themekit-piu/Languages/en.ini
new file mode 100644
index 0000000000..584a601c75
--- /dev/null
+++ b/Themes/_themekit-piu/Languages/en.ini
@@ -0,0 +1,57 @@
+[Common]
+WindowTitle=THEMEKIT PIU
+
+[Judgment]
+W1=TERRIFIC
+W2=PERFECT
+W3=GREAT
+W4=GOOD
+W5=BAD
+Miss=MISS
+
+[OptionTitles]
+OptionsMode=Options Type
+
+[OptionExplanations]
+OptionsMode=magic
+
+[OptionNames]
+0.5x=0.5x
+1.5x=1.5x
+1x=1x
+2x=2x
+3x=3x
+4x=4x
+5x=5x
+6x=6x
+7x=7x
+8x=8x
+
+Speed=Speed
+Noteskins=Noteskins
+FadeNotes=Fade Notes
+Scroll=Scroll
+Effect=Effect
+Receptor=Receptor
+ResetOptions=Reset Options
+
+Vanish=Vanish
+RndVanish=Random Vanish
+Appear=Appear
+Nonstep=Nonstep
+
+Accel=Acceleration
+Decel=Deceleration
+Worm=EarthWorm
+
+Spin=Spin
+Snake=Snake
+Drift=Drift
+Shrink=Shrink
+Jumps=Jumps
+
+Freedom=Freedom
+Center=Center
+
+Codes=Custom Code Detector
+OptionsList=Custom Options List
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Scripts/01 system.lua b/Themes/_themekit-piu/Scripts/01 system.lua
new file mode 100644
index 0000000000..2b4ede28dc
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/01 system.lua
@@ -0,0 +1,18 @@
+ThemeInfo = {
+ Name="_Themekit_PIU";
+ Version="pretty much final";
+ Code="DSMT-PIUKIT";
+ Date = {31,7,2010};
+};
+
+WORKING_VERSION = (ProductVersion() == "v1.0 rc2")
+
+if GetUserPrefB("OptionsMode") == nil then
+ SetUserPref("OptionsMode", false)
+end
+
+--no anda así, mejor uso pantallas
+--assert(SSC and WORKING_VERSION, "El Themekit PIU es compatible sólo con SM-SSC")
+
+--not working like this, better use screens
+--assert(SSC and WORKING_VERSION, "Themekit PIU is compatible only with SM-SSC RC1.5")
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Scripts/02 CustomCodeDetector.lua b/Themes/_themekit-piu/Scripts/02 CustomCodeDetector.lua
new file mode 100644
index 0000000000..cdf0cf4c71
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/02 CustomCodeDetector.lua
@@ -0,0 +1,350 @@
+--moved here for portability sake
+--[[--------------------------------------------------------------------------
+Custom Code Detector by Daisuke Master
+------------------------------------------------------------------------------
+-= Whats this? =-
+Just that, a custom codedetector, you can add the codenames as exact mods
+and this thingy will do whatever you wanted to do with the oh-so-known
+harcoded codedetector.
+I kind of don't like the codedetector for various reasons, that's why I made
+this (also the remaining stuff happened by accident lol), anyway, if you feel
+like wanting this in your theme, go ahead! no problem, just let me know that
+you're using it and that this was useful for you ^^
+
+-= How to use =-
+First of all, put this lua module under the Scripts folder of your theme.
+Using codeset, put this in a CodeMessageCommand, inside a function command,
+under ScreenSelectMusic, like this:
+
+
+CodeMessageCommand=function(self)
+ CustomCodeDetector()
+end;
+
+
+You'll need codename and player to be passed as arguments, you can get those
+somewhere:
+
+
+CodeMessageCommand=function(self,params)
+ CustomCodeDetector(params.Name, params.PlayerNumber)
+end;
+
+
+If you like to be classy like me:
+
+
+CodeMessageCommand=function(self,params)
+ local code = params.Name
+ local player = params.PlayerNumber
+ if not GAMESTATE:IsHumanPlayer(player) then return end;
+
+ CustomCodeDetector(code, player)
+end;
+
+
+Niceties:
+
+
+CodeMessageCommand=function(self,params)
+ local code = params.Name
+ local player = params.PlayerNumber
+ if not GAMESTATE:IsHumanPlayer(player) then return end;
+
+ if CustomCodeDetector(code, player, true) then
+ --idk what to put here so eh...
+ else
+ --handle here other codes for misc purposes
+ end
+
+ SOUND:PlayOnce(THEME:GetPathS("ScreenSelectMusic","Options"))
+end;
+
+Extras: you can set a third param as true to deactivate sound and
+the message broadcast to handle those outside (example above)
+
+What more? Oh yes, you'll need a CodeNames line under ScreenSelectMusic
+
+
+[ScreenSelectMusic]
+CodeNames="Noteskin,Speed,Cancel,Dark,Mirror"
+;main codes
+CodeNoteskin="Up,Up,Down,Down,Left,Right,Left,Right"
+CodeSpeed="Left,Right,Left,Right,Down"
+CodeCancel="Select,Select"
+;secondary codes
+CodeDark="Down,Down,Left,Right,Down"
+CodeMirror="Down,Left,Up,Down,Right,Up"
+
+
+The first three (speed, noteskin and cancle er... cancel) are mandatory, the
+rest are optional (dark and mirror as examples)
+
+-= Caveats =-
+*I don't know what will happen if illegal modifiers are set into the CodeNames
+line under ScreenSelectMusic, so try at your own risk (not that anything bad
+but a crash may happen, I don't know so I'm just warning you).
+*I don't know what will happen if you add percentages and/or approach into the
+modifiers (for example >Code50% tornado="@Right-Up")
+*Ignore the previous two points, I just added a mod validator function, if your
+mod does not exists there just add it.
+*You just can't set multiple modifiers in one code because of how codes are
+separated (by commas)
+*FOR PUMP-SM USERS: Watch out when using center as part of your code, it's
+treated as start button and you know what happens when you press start,
+solution: you can use two part selection in metrics along with twopart
+confirms only so you can doublepress center with no problems, remember that
+only sm-ssc can do that (goes the same to ez2/popn users with footdown/red
+buttons).
+*Don't try weird things with this.
+
+-= TODO list =-
+*Previous speed and noteskins
+*Go lazy and lowercase GetPlayerOptions
+*Be able to put multiple mods in one code
+
+-= Licensing =-
+IMO it's important, I don't like to see my work being hijacked by someone else
+and claiming as it's own (others don't like that either) so here we go:
+
+I'm licensing this under Creative Commons by-sa 3.0
+http://creativecommons.org/licenses/by-sa/3.0/
+
+This means that:
+
+You can share and adapt this code as you like/need/want withouth worry, but
+you must attribute me, and if you release your modified work you must license
+it with the same license as this.
+
+-= Credits =-
+DaisuMaster
+
+-= Thanks =-
+main stepmania devteam (they created SM)
+sm-ssc devteam (they forked sm4 and tweaked it in an astounding way)
+cesarmades (this guy inspired me somehow)
+
+-= Final notes =-
+That's all you should need to know for now, and as I said, feel free to use
+this and let me know if this was useful for you ^^
+--]]--------------------------------------------------------------------------
+function ReadSpeedMods()
+ --this reads speeds from a file (Cmods are not allowed, I don't like to
+ --deal with these)
+ local dir = THEME:GetCurrentThemeDirectory() .. "speeds.txt"
+ local speeds = File.Read( dir )
+ if not speeds then
+ speeds = {"1x","2x","3x","4x","5x","8x"}
+ speeds = join("\r\n",speeds)
+ File.Write( dir , speeds)
+ return speeds
+ end
+
+ speeds = string.gsub(speeds,"\r","")
+ speeds = split("\n", speeds)
+
+ --[[local rebuild = false
+ for k,v in ipairs(speeds) do
+ if not string.find(v,"%dx") or not string.find(v,"%%d.dx") then
+ rebuild = true
+ table.remove(speed,k)
+ end
+ end
+ if rebuild then
+ --cleanup
+ File.Write( dir , join("\r\n",speeds))
+ end]]
+
+ return speeds
+end
+
+local function IsValidMod(m)
+ --check mods here, see PlayerOptions.cpp if you want/need more
+ --throwing the most common/used here
+ --todo: regex formats and bind the mods into a table so setups like 50% dark would work
+ if m == "Boost"
+ or m == "Brake"
+ or m == "Wave"
+ or m == "Expand"
+ or m == "Boomerang"
+ or m == "Drunk"
+ or m == "Dizzy"
+ or m == "Confusion"
+ or m == "Mini"
+ or m == "Tiny"
+ or m == "Flip"
+ or m == "Invert"
+ or m == "Tornado"
+ or m == "Tipsy"
+ or m == "Bumpy"
+ or m == "Beat"
+ or m == "XMode"
+ or m == "Hidden"
+ or m == "Sudden"
+ or m == "Stealth"
+ or m == "Blink"
+ or m == "RandomVanish"
+ or m == "Reverse"
+ or m == "Split"
+ or m == "Alternate"
+ or m == "Cross"
+ or m == "Centered"
+ or m == "Dark"
+ or m == "RandomAttacks"
+ or m == "SongAttacks"
+ or m == "PlayerAutoPlay"
+ or m == "Mirror"
+ or m == "Left"
+ or m == "Right"
+ or m == "Shuffle"
+ or m == "SoftShuffle"
+ or m == "SuperShuffle"
+ then
+ return true
+ else
+ return false
+ end
+end
+
+--local function Tracef(...) Trace(string.format(...)) end
+
+function CustomCodeDetector(code,player,sound_and_broadcast)
+ assert(code,"[CUSTOMCODEDETECTOR]: an input code must be given.")
+ assert(player, "[CUSTOMCODEDETECTOR]: a player number must be given.")
+ if sound_and_broadcast then
+ Trace("[CUSTOMCODEDETECTOR]: playeroptions message broadcast and sound playback are deactivated")
+ end
+ --playerstates lets you get and set modifiers per player via lua
+ local playerstate = GAMESTATE:GetPlayerState(player)
+ --nice, I didn't knew that playermods could be get as an array.
+ local playermods = playerstate:GetPlayerOptionsArray('ModsLevel_Preferred')
+ --local playermods = playerstate:GetPlayerOptions('ModsLevel_Preferred')
+ --playermods = split(", ",playermods)
+
+ local noteskins = NOTESKIN:GetNoteSkinNames()
+ if not noteskins then noteskins = {"default"} end
+ --woot! noteskins via codes!! and not hardcoded!!! :awesome:
+ --dang, I forgot that GetNoteSkinNames works only in sm-ssc
+ if code == "Noteskin" and SSC then
+
+ --do changes here
+ local found = false
+ --iterate every noteskin in every playermod
+ for i,j in ipairs(playermods) do
+ for k,l in ipairs(noteskins) do
+ --we got a match
+ if j == l then
+ found = true
+ local index = k+1
+ --avoiding overflow
+ if index > #noteskins then index = 1 end
+ --replacing
+ Tracef("[CUSTOMCODEDETECTOR]: Setting noteskin '%s' in place of '%s'", noteskins[index], playermods[i])
+ playermods[i] = noteskins[index]
+ end
+ end
+ end
+
+ --no matches
+ if not found then
+ for k,v in ipairs(noteskins) do
+ if string.lower(v) == "default" then
+ --set the one next to default or the first if it's the last
+ local idx = k+1
+ if idx > #noteskins then idx = 1 end
+ Tracef("[CUSTOMCODEDETECTOR]: Setting noteskin '%s'", noteskins[idx])
+ table.insert(playermods, noteskins[idx])
+ end
+ end
+ end
+ --like notekins but with speeds
+ elseif code == "Speed" then
+ --read your speeds from a file (by theme)
+ --local speeds = { "1x","2x","3x","4x","5x" }
+ local speeds = ReadSpeedMods()
+ local found = false
+
+ for i,j in ipairs(playermods) do
+ for k,l in ipairs(speeds) do
+ if j == l then
+ found = true
+ local index = k+1
+ if index > #speeds then index = 1 end
+ Tracef("[CUSTOMCODEDETECTOR]: Setting speedmod '%s' in place of '%s'", speeds[index], playermods[i])
+ playermods[i] = speeds[index]
+ end
+ end
+ end
+ if not found then
+ --most likely is a 1x, set the next
+ for k,v in ipairs(speeds) do
+ if v == "1x" then
+ local idx = k+1
+ if idx > #speeds then idx = 1 end
+ Tracef("[CUSTOMCODEDETECTOR]: Setting speedmod '%s'", speeds[idx])
+ table.insert(playermods, speeds[idx])
+ end
+ end
+ end
+ elseif code == "Cancel" then
+ local defaultmods = PREFSMAN:GetPreference("DefaultModifiers")
+ defaultmods = split(",", defaultmods)
+ --set 1x and clear other mods, also default noteskin (along with the default mods)
+ playermods = { "1x","default" }
+ for k,v in ipairs(defaultmods) do
+ table.insert(playermods, v)
+ end
+ else
+ if IsValidMod(code) then
+ --other mod codes, code name must be the exact mod
+ local found = false
+ for i,j in ipairs(playermods) do
+ if j == code then
+ --remove it
+ found = true
+ Tracef("[CUSTOMCODEDETECTOR]: Setting modifier '%s'", code)
+ table.remove(playermods, i)
+ end
+ end
+
+ if not found then
+ Tracef("[CUSTOMCODEDETECTOR]: Unsetting modifier '%s'", code)
+ table.insert(playermods, code)
+ end
+ else
+ --SOUND:PlayOnce(THEME:GetPathS("MusicWheel","locked"))
+ Tracef("[CUSTOMCODEDETECTOR]: The mod '%s' could not be set", code)
+ return false
+ end
+ end
+
+ --let's check if noteskins aren't missing (we're avoiding crashes here...)
+ local found = false
+ --iterate again uh
+ for i,j in ipairs(playermods) do
+ for k,l in ipairs(noteskins) do
+ if j == l then
+ found = true
+ end
+ end
+ end
+ --apparently there aren't any noteskins...
+ if not found then
+ table.insert(playermods, "default")
+ end
+
+ --join
+ playermods = join(", ",playermods)
+
+ --set the mods
+ playerstate:SetPlayerOptions('ModsLevel_Preferred',playermods)
+ --optional stuff
+ if not sound_and_broadcast then
+ --play some sound
+ SOUND:PlayOnce(THEME:GetPathS("ScreenSelectMusic","Options"))
+ --send some message
+ MESSAGEMAN:Broadcast("PlayerOptionsChanged", { PlayerNumber = player })
+ end
+ --if we get here then everything went just fine
+ return true
+end
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Scripts/02 Draw.lua b/Themes/_themekit-piu/Scripts/02 Draw.lua
new file mode 100644
index 0000000000..3e98a3971d
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/02 Draw.lua
@@ -0,0 +1,252 @@
+--[[--------------------------------------------------------------------------
+Shape Drawing module by Daisuke Master
+------------------------------------------------------------------------------
+-= What's this? =-
+Those are functions that can draw some basic shapes
+
+-= How to use =-
+Add them as layers
+
+
+Def.ActorFrame {
+ Draw.RoundBox(410,310,20,20,color(#000000));
+ Draw.RoundBox(400,300,10,10);
+ Draw.Box(256,64,color("#ffcc66"))..{
+ InitCommand=cmd(y,-300);
+ };
+}
+
+
+You'll need graphics included under Graphics/_shapes for the roundboxes and
+ovals (a 1000x1000 circle, 500x500 quarter circle and 1000x850 triangle)
+
+The neatest thing about those things is that those are overloaded:
+
+Boxes (pretty much same as quads but without the need of using initcommand
+every fucking time to resize them, color them and agh!...)
+Draw.Box(width) <-- this will make a blank square (it says blank not black)
+Draw.Box(width,color) <-- this will make a colored square
+Draw.Box(width,height) <------------ Rectangles!
+Draw.Box(width,height,color) <--/
+
+Triangles (BROKEN)
+Draw.Triangle(base) <-- this will make an equilateral blank trine
+Draw.Triangle(base,color) <-- colored equilateral trine
+Draw.Triangle(base,height)
+Draw.Triangle(base,height,color)
+Draw.Triangle(base,height,point)
+Draw.Triangle(base,height,point,color)
+--planned/impossible
+Draw.Triangle(base,point,color) <-- sorry, I can't figure how to do this
+ (maybe if I use negative values...)
+Draw.Triangle(base,skew) <-- rect/irregular trines
+Draw.Triangle(base,skew,color)
+--the point should be in 0..1 range
+
+RoundBoxes (cute rounded boxes, better than sharp edged boxes)
+Draw.RoundBox(width,height)
+Draw.RoundBox(width,height,color)
+Draw.RoundBox(width,height,radius)
+Draw.RoundBox(width,height,radius,color)
+Draw.RoundBox(width,height,horiz_radius,vert_radius,color)
+
+Ovals/Circles (yes, figures)
+Draw.Oval(radius)
+Draw.Oval(radius,color)
+Draw.Oval(radius1,radius2)
+Draw.Oval(radius1,radius2,color)
+
+Lines (not yet)
+how it's (supposed to be) drawn:
+S = start
+E = end
+dash,slash,backslash,bar = line body
+
+Draw.Line(4,0,0,4)
+ E
+ /
+ /
+ /
+S
+
+Draw.Line(0,0,4,0)
+S---E
+
+Draw.Line(0,0,4,4)
+S
+ \
+ \
+ \
+ E
+
+Draw.Line(0,0,0,4)
+S
+|
+|
+|
+E
+
+lines are pending...
+--]]--------------------------------------------------------------------------
+
+Draw = {
+ Box = function(w,...)
+ assert(w)
+ local h,c = ...
+ if not h and not c then
+ h = w
+ c = color("#ffffff")
+ elseif not c then
+ if type(h) == "number" then
+ c = color("#ffffff")
+ else
+ c = h
+ h = w
+ end
+ end
+ --option
+ --if not h then h = w end
+ --if not c then c = color("#ffffff") end
+ return Def.Quad {
+ InitCommand=function(self)
+ self:basezoomx(w);
+ self:basezoomy(h);
+ self:diffuse(c);
+ end;
+ };
+ end;
+ Triangle = function(b,h,p,c)
+ --I'M BROKEN
+ assert(b)
+ assert(h)
+ assert(p)
+ assert(c)
+ --local h,p,c = ...
+
+ return LoadActor(THEME:GetPathG("","_Figures/triangle.png"))..{
+ InitCommand=function(self)
+ local base = self:GetWidth()
+ local height = self:GetHeight()
+ local xzoom = scale(b,0,base,0,1)
+ local yzoom = scale(h,0,height,0,1)
+ local rot = scale(p,0,1,0,360)
+ self:basezoomx(xzoom);
+ self:basezoomx(yzoom);
+ self:baserotationz(rot);
+ self:diffuse(c);
+ end;
+ };
+ end;
+ --I had to take a small glance into optical's roundbox code to do this...
+ RoundBox = function(w,h,...)
+ assert(w)
+ assert(h)
+ --grab color and radii from arguments
+ local hr,vr,c = ...
+ if not hr and not vr and not c then
+ hr = 10
+ vr = 10
+ c = color("#ffffff")
+ elseif not vr and not c then
+ if type(hr) == "number" then
+ vr = hr
+ c = color("#ffffff")
+ else
+ c = hr
+ hr = 10
+ vr = 10
+ end
+ elseif not c then
+ if type(vr) == "number" then
+ c = color("#ffffff")
+ else
+ c = vr
+ vr = hr
+ end
+ end
+ --horizontal radius can't overflow the half of the width and can't be
+ --below zero, same with vertical radius
+ hr = clamp(hr,0,w/2)
+ vr = clamp(vr,0,h/2)
+
+ local corner = LoadActor(THEME:GetPathG("","_Figures/corner.png"))..{
+ InitCommand=function(self)
+ local width = self:GetWidth()
+ local height = self:GetHeight()
+ local xpixels = scale(hr,0,width,0,1)
+ local ypixels = scale(vr,0,height,0,1)
+ self:basezoomx(xpixels)
+ self:basezoomy(ypixels)
+ end;
+ };
+
+ return Def.ActorFrame {
+ InitCommand=function(self)
+ --this's pretty a shitload of operations...
+ self:GetChild("Top"):y(-h/2+vr/2);
+ self:GetChild("Bottom"):y(h/2-vr/2);
+ --also here
+ self:GetChild("TopLeft"):xy(-w/2+hr/2,-h/2+vr/2);
+ self:GetChild("TopRight"):xy(w/2-hr/2,-h/2+vr/2);
+ self:GetChild("BottomLeft"):xy(-w/2+hr/2,h/2-vr/2);
+ self:GetChild("BottomRight"):xy(w/2-hr/2,h/2-vr/2);
+ --coloree :3
+ self:runcommandsonleaves(cmd(diffuse,c))
+ end;
+ --lol sound effects
+ --wrrr whrr wrrr
+ Draw.Box(w-hr-hr,vr,c)..{Name="Top"};
+ Draw.Box(w,h-vr-vr,c)..{Name="Middle"};
+ Draw.Box(w-hr-hr,vr,c)..{Name="Bottom"};
+ --corners
+ corner..{ Name="TopLeft"; };
+ corner..{ Name="TopRight"; BaseRotationY=180; };
+ corner..{ Name="BottomLeft"; BaseRotationX=180; };
+ corner..{ Name="BottomRight"; BaseRotationX=180; BaseRotationY=180; };
+ }
+ end;
+ Oval = function(w,...)
+ assert(w)
+ local h,c = ...
+ if not h and not c then
+ h = w
+ c = color("#ffffff")
+ elseif not c then
+ color("#ffffff")
+ if type(h) == "number" then
+ c = color("#ffffff")
+ else
+ c = h
+ h = w
+ end
+ end
+ return LoadActor(THEME:GetPathG("","_Figures/circle.png"))..{
+ InitCommand=function(self)
+ --self:SetTextureFiltering(false);
+ local width = self:GetWidth()
+ local height = self:GetHeight()
+ local xzoom = scale(w,0,width,0,1)
+ local yzoom = scale(h,0,height,0,1)
+ self:diffuse(c);
+ self:basezoomx(xzoom);
+ self:basezoomy(yzoom);
+ end;
+ };
+ end;
+ Line = function(x1,x2,y1,y2,c)
+ assert(x1)
+ assert(x2)
+ assert(y1)
+ assert(y2)
+
+ return Def.Quad {
+ InitCommand=function(self)
+ self:horizalign(left);
+ self:xy(x1,y1);
+ self:zoomto(1,1);
+ self:rotationz(0);
+ self:diffuse(c);
+ end;
+ };
+ end
+}
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Scripts/02 ini read.lua.bak b/Themes/_themekit-piu/Scripts/02 ini read.lua.bak
new file mode 100644
index 0000000000..a72fbb797b
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/02 ini read.lua.bak
@@ -0,0 +1,71 @@
+--iniread
+--references: http://lua.pastebin.com/fef286
+
+--[[function FirstCharMatch(text,pattern)
+ local count = 1
+ while true do
+ if string.sub(text,count,count) == pattern then
+ return count
+ end
+ count = count+1
+ end
+end]]
+
+function ReadIniFile( file )
+ local path = ResolveRelativePath( file, 2 )
+ assert(path, file .. " was not found")
+
+ local inifile = File.Read( path )
+ local lines = {}
+
+ --identify mac, unix or dos
+ --mac "\r" - cr
+ if string.find(inifile, "\r") ~= nil
+ and string.find(inifile, "\n") == nil
+ then
+ lines = split("\r", inifile)
+ --unix "\n" - lf
+ elseif string.find(inifile, "\r") == nil
+ and string.find(inifile, "\n") ~= nil
+ then
+ lines = split("\n", inifile)
+ --dos/win "\r\n" -crlf
+ elseif string.find(inifile, "\r") ~= nil
+ and string.find(inifile, "\n") ~= nil
+ then
+ lines = split("\r\n", inifile)
+ end
+
+ local ret = {}
+ for k,v in ipairs(lines) do
+ if string.sub(v,1,1) == '[' then
+
+ end
+ end
+
+ return {}
+end
+--[[--------------------
+[Section1]
+Key1=value1
+Key2=value2
+Key3=value3
+
+[Section2]
+Key1=value1
+Key2=value2
+Key3=value3
+
+ini = {
+ Section1 = {
+ Key1 = "Value1";
+ Key2 = "Value2";
+ Key3 = "Value3";
+ };
+ Section2 = {
+ Key1 = "Value1";
+ Key2 = "Value2";
+ Key3 = "Value3";
+ };
+}
+--]]--------------------
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Scripts/02 splitmode.lua b/Themes/_themekit-piu/Scripts/02 splitmode.lua
new file mode 100644
index 0000000000..836170fa01
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/02 splitmode.lua
@@ -0,0 +1,102 @@
+--SplitMode (no version)
+--[[--------------------------------------------------------------------------
+Inspired by FSX's SplitLoader (ExSongs)
+A Note: No code was stolen from FSX's script, this was completely made from
+scratch (the only stolen thing was the idea of using the description as helper
+lol) This is a minimized version, without accurate searching modes, prefs and
+stuff. This only searches for a song specified in the description and sets
+it along with the same kind of source difficulty and stepstype.
+
+~{ How to use? }~
+Write into steps description:
+!SONG=
+This script will do the rest...
+
+~{ Where to use? }~
+Anywhere before gameplay starts
+(Recommended: ScreenStage or ScreenStageInformation)
+
+~{ TODO list }~
+>none...
+
+~{ Credits }~
+FSX: he had the initial ex-songs idea, I arranged that idea to make it
+simplier and somewhat flexible
+
+~{ License }~
+cc-by
+http://creativecommons.org/licenses/by/3.0/
+In a nutshell: You are free to use this freely without worry, just atribute me
+--]]--------------------------------------------------------------------------
+function SplitMode()
+ local bImWorking = false
+
+ --local function Tracef(...) Trace(string.format(...)) end
+
+ --I'll work with the master player
+ local masterplayer = GAMESTATE:GetMasterPlayerNumber()
+ local song = GAMESTATE:GetCurrentSong()
+ local step = GAMESTATE:GetCurrentSteps(masterplayer)
+ local description = step:GetDescription()
+ --Working for 1 player atm...
+
+ --if string.lower( step:GetDifficulty() ) ~= 'difficulty_edit' then
+ if not step:IsAPlayerEdit() then
+ if description ~= "" then
+ --the description it's multipurpose
+ local parts = split("|", description);
+ local working = {}
+
+ for i=1,#parts do
+ if string.find(parts[i], "!SONG") then
+ --use equals as separator
+ working = split("=", parts[i])
+ end
+ end
+
+ if #working == 2 then
+ --two parts
+ if working[1] == "!SONG" and working[2] ~= "" then
+ local songtoset = SONGMAN:FindSong(working[2])
+ --Lets check if there is a song...
+ if songtoset ~= nil then
+ local steptoset = songtoset:GetOneSteps(step:GetStepsType(), step:GetDifficulty())
+ if steptoset ~= nil then
+ --Yay!
+ GAMESTATE:SetCurrentSong(songtoset)
+ --Set MasterPlayer's steps to both players.
+ for idx, player in ipairs(PlayerNumber) do
+ GAMESTATE:SetCurrentSteps(player, steptoset)
+ end
+ bImWorking = true
+ Trace("[SPLITMODE]: Split System Is Working...")
+ Tracef("--> NewSong: '%s - %s'", songtoset:GetDisplayFullTitle(), songtoset:GetDisplayArtist())
+ --Tracef("--> NewDifficulty: '%s'",steptoset:GetStepsType())
+ --Tracef("--> NewStepType: '%s'",steptoset:GetDifficulty())
+ Trace("--> Difficulty and StepsType should be the same as the source song")
+ else
+ Tracef("[SPLITMODE]: Steps with StepsType '%s' and Difficulty '%s' not found for the song '%s'...", step:GetStepsType(), step:GetDifficulty(), parts[2])
+ --Tracef("[SPLITMODE]: No StepsType and Difficulty Match for song '%s'...", parts[2]);
+ end
+ else
+ Tracef("[SPLITMODE]: Song '%s' not found...", working[2]);
+ end
+ else
+ Trace("[SPLITMODE]: Do nothing: Malformed Working Part Format")
+ end
+ else
+ Trace("[SPLITMODE]: Do nothing: Regular or Reserved Description")
+ end
+ else
+ Trace("[SPLITMODE]: Do nothing: Empty Description")
+ end
+ else
+ Trace("[SPLITMODE]: Do nothing: Secure Exception -> This is either an edit or a player edit")
+ end
+
+-- if not bImWorking then
+-- Trace("[SPLITMODE]: Not working for an unknown reason...")
+-- end
+
+ return bImWorking
+end
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Scripts/03 branches.lua b/Themes/_themekit-piu/Scripts/03 branches.lua
new file mode 100644
index 0000000000..fa551ae645
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/03 branches.lua
@@ -0,0 +1,39 @@
+function GameplayNext()
+ --Cuando pierdas
+ if STATSMAN:GetCurStageStats():AllFailed() then
+ --Pierdes, fuera
+ return "ScreenStageBreak"
+ --Pasaste!
+ else
+ return "ScreenEvaluationNormal"
+ end
+end
+
+function EvaluationNext()
+ local stagesleft = GAMESTATE:GetSmallestNumStagesLeftForAnyHumanPlayer()
+ if (stagesleft <= 0 or STATSMAN:GetBestGrade() >= 6) and not GAMESTATE:IsEventMode() then
+ --return "ScreenGameOver"
+ return "ScreenProfileSave"
+ else
+ return "ScreenNextStage"
+ end
+end
+
+function GameOverNext()
+ if (GAMESTATE:GetCoinMode() == 'CoinMode_Pay' and GAMESTATE:GetCoins() > 0)
+ or GAMESTATE:GetCoinMode() == 'CoinMode_Free'
+ then
+ return "ScreenTitleMenu"
+ else
+ return "ScreenInit"
+ end
+end
+
+function StageBreakNext()
+ if GAMESTATE:IsEventMode() then
+ return "ScreenSelectMusic"
+ else
+ --return "ScreenGameOver"
+ return "ScreenProfileSave"
+ end
+end
diff --git a/Themes/_themekit-piu/Scripts/03 optionrow.lua b/Themes/_themekit-piu/Scripts/03 optionrow.lua
new file mode 100644
index 0000000000..96ae18ca75
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/03 optionrow.lua
@@ -0,0 +1,90 @@
+--[[--------------------------------------------------------------------------
+A fresh and simple way to set up OptionRows -DaisuMaster
+--]]--------------------------------------------------------------------------
+
+--[[ CORE FUNCTIONS ]]--
+--{ Those must be internal only }--
+
+-- Main template
+local function OptionRowTemplate(name,layout,select,onechoice,export,choices,loadfunc,savefunc)
+ local t = {
+ Name = name;
+ LayoutType = layout;
+ SelectType = select;
+ OneChoiceForAllPlayers = onechoice;
+ ExportOnChange = export;
+ Choices = choices;
+ LoadSelections = loadfunc;
+ SaveSelections = savefunc;
+ }
+ setmetatable( t, t )
+ return t
+end
+
+-- Create templates for UserPreferences
+local function OptionRowUserPrefTemplate(name,choices)
+ local function load(self, list, pn)
+ if GetUserPrefB(name) then
+ list[1] = true
+ else
+ list[2] = true
+ end
+ end
+ local function save(self, list, pn)
+ local bool
+ if list[1] then
+ bool = true
+ else
+ bool = false
+ end
+ SetUserPref(name,bool)
+ end
+ return OptionRowTemplate(name,"ShowAllInRow","SelectOne",true,false,choices,load,save)
+end
+
+-- Same as above but for EnvUtils
+local function OptionRowEnvutilsTemplate(name,onechoice,choices)
+ local function load(self, list, pn)
+ if onechoice then
+ setenv(name,false)
+ else
+ setenv(name..pn,false)
+ end
+ list[1] = true
+ end
+ local function save(self, list, pn)
+ local bool
+ if list[1] then
+ bool = false
+ else
+ bool = true
+ end
+ if onechoice then
+ setenv(name,bool)
+ else
+ setenv(name..pn,bool)
+ end
+ end
+ if not choices then
+ choices = {
+ THEME:GetString("OptionNames","Off"),
+ THEME:GetString("OptionNames","On"),
+ }
+ end
+ return OptionRowTemplate(name,"ShowAllInRow","SelectOne",onechoice,false,choices,load,save)
+end
+
+--[[ whatever else you want/like put it there (keep it clean please) ]]--
+--{ Those should be used externally }--
+
+function OptionReverseGrade()
+ return OptionRowEnvutilsTemplate("GradeReverse",false)
+end
+
+function UserPrefOptionsMode()
+ local choices = {
+ THEME:GetString("OptionNames","OptionsList"),
+ THEME:GetString("OptionNames","Codes"),
+ }
+ return OptionRowUserPrefTemplate("OptionsMode", choices)
+end
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Scripts/04 themelibs.lua b/Themes/_themekit-piu/Scripts/04 themelibs.lua
new file mode 100644
index 0000000000..af8682ff06
--- /dev/null
+++ b/Themes/_themekit-piu/Scripts/04 themelibs.lua
@@ -0,0 +1,153 @@
+function StageBreak()
+ if GAMESTATE:IsEventMode()
+ or GAMESTATE:GetEasiestStepsDifficulty() == 'Difficulty_Beginner'
+ or GAMESTATE:GetEasiestStepsDifficulty() == 'Difficulty_Easy'
+ then
+ return -1
+ end
+
+ return 51
+end
+
+function JudgmentTransformCommand( self, params )
+ local y = 0
+
+ if params.bCentered then
+ if params.bReverse then
+ y = 100
+ else
+ y = -170
+ end
+ end
+
+ self:y(y)
+end
+
+function Tracef(...)
+ Trace(string.format(...))
+end
+
+function DifficultyAndStepstypeToString( difficulty, stepstype, description )
+ --safe
+ difficulty = string.lower(difficulty)
+ stepstype = string.lower(stepstype)
+ --
+ description = description == "" and "Edit" or description
+ if string.find(stepstype,"double") then
+ description = description.." - Double"
+ else
+ description = description.." - Single"
+ end
+
+ --return {difficulty, stepstype, description}
+
+ local strings = {
+ stepstype_pump_single = {
+ difficulty_beginner = "Easy";
+ difficulty_easy = "Normal";
+ difficulty_medium = "Hard";
+ difficulty_hard = "Crazy";
+ difficulty_challenge = "Wild";
+ difficulty_edit = description;
+ };
+ stepstype_pump_double = {
+ difficulty_beginner = "Double";
+ difficulty_easy = "Performance";
+ difficulty_medium = "Freestyle";
+ difficulty_hard = "Nightmare";
+ difficulty_challenge = "Hardcore";
+ difficulty_edit = description;
+ };
+ stepstype_pump_halfdouble = {
+ --figure out more names to identify
+ difficulty_beginner = "Halfdouble";
+ difficulty_easy = "Halfdouble";
+ difficulty_medium = "Halfdouble";
+ difficulty_hard = "Halfdouble";
+ difficulty_challenge = "Halfdouble";
+ difficulty_edit = description;
+ };
+ other = {
+ --touhou, sorry
+ difficulty_beginner = "Easy";
+ difficulty_easy = "Normal";
+ difficulty_medium = "Hard";
+ difficulty_hard = "Lunatic";
+ difficulty_challenge = "Extra";
+ difficulty_edit = description;
+ };
+ }
+
+ local game = GAMESTATE:GetCurrentGame():GetName()
+ local mode = string.gsub(stepstype,game.."_","")
+ mode = string.gsub(mode,"stepstype_","")
+
+ --if game == mode then mode = "" else mode = "-"..mode end
+
+ local FallbackString = string.format("%s-%s %s", game, mode, strings.other[difficulty])
+
+ local ret = strings[stepstype]
+ if not ret then return FallbackString end
+
+ return ret[difficulty] or FallbackString
+end
+-->> media loaders
+function LoadSound( a, b ) return LoadActor( THEME:GetPathS(b and a or "", b or a) ) end;
+--<< end media loaders
+-->> positioning helpers (handy!)
+function Actor:FromCenterX(i)
+ self:x(SCREEN_CENTER_X + i)
+end
+
+function Actor:FromCenterY(i)
+ self:y(SCREEN_CENTER_Y + i)
+end
+
+function Actor:FromLeft(i)
+ self:x(SCREEN_LEFT + i)
+end
+
+function Actor:FromRight(i)
+ self:x(SCREEN_RIGHT + i)
+end
+
+function Actor:FromTop(i)
+ self:y(SCREEN_TOP + i)
+end
+
+function Actor:FromBottom(i)
+ self:y(SCREEN_BOTTOM + i)
+end
+--<< end positioning helpers
+-->> scale helpers
+--like stretchto, but the values are relative to the edges
+function Actor:Rect(left, top, right, bottom)
+ self:stretchto(left, top, SCREEN_RIGHT - right, SCREEN_BOTTOM - bottom);
+end
+
+function Actor:Skew(x,y)
+ self:skewx(x);
+ self:skewy(x);
+end
+
+--I wonder if it's like that...
+function Actor:SkewPixels(x,y)
+ self:skewx(scale(x,0,self:GetWidth(),0,1));
+ self:skewy(scale(y,0,self:GetHeight(),0,1));
+end
+--<< end scale helpers
+-->> frame set helpers
+function Sprite.FrameRange(s,f,d)
+ local frames = {}
+ for i=s,f do
+ frames[#frames+1] = {
+ Frame = i;
+ Delay = d;
+ };
+ end
+ return frames
+end
+--<< end frame set helpers
+
+--Alberto Ramos
+--MIT License
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/2-1.ogg b/Themes/_themekit-piu/Sounds/2-1.ogg
new file mode 100644
index 0000000000..97a40e4fd1
Binary files /dev/null and b/Themes/_themekit-piu/Sounds/2-1.ogg differ
diff --git a/Themes/_themekit-piu/Sounds/3-2.ogg b/Themes/_themekit-piu/Sounds/3-2.ogg
new file mode 100644
index 0000000000..bbbe57f8bb
Binary files /dev/null and b/Themes/_themekit-piu/Sounds/3-2.ogg differ
diff --git a/Themes/_themekit-piu/Sounds/B09.ogg b/Themes/_themekit-piu/Sounds/B09.ogg
new file mode 100644
index 0000000000..a5c10eb561
Binary files /dev/null and b/Themes/_themekit-piu/Sounds/B09.ogg differ
diff --git a/Themes/_themekit-piu/Sounds/Common Coin.redir b/Themes/_themekit-piu/Sounds/Common Coin.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/Common Coin.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/Common Start.redir b/Themes/_themekit-piu/Sounds/Common Start.redir
new file mode 100644
index 0000000000..a3850946fe
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/Common Start.redir
@@ -0,0 +1 @@
+2-1.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/Copia de ScreenSelectMusic locked.redir b/Themes/_themekit-piu/Sounds/Copia de ScreenSelectMusic locked.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/Copia de ScreenSelectMusic locked.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/MusicWheel change.redir b/Themes/_themekit-piu/Sounds/MusicWheel change.redir
new file mode 100644
index 0000000000..cf2dcaddd7
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/MusicWheel change.redir
@@ -0,0 +1 @@
+3-2.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/MusicWheel expand.redir b/Themes/_themekit-piu/Sounds/MusicWheel expand.redir
new file mode 100644
index 0000000000..cf2dcaddd7
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/MusicWheel expand.redir
@@ -0,0 +1 @@
+3-2.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/MusicWheel locked.redir b/Themes/_themekit-piu/Sounds/MusicWheel locked.redir
new file mode 100644
index 0000000000..cf2dcaddd7
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/MusicWheel locked.redir
@@ -0,0 +1 @@
+3-2.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/Player mine.redir b/Themes/_themekit-piu/Sounds/Player mine.redir
new file mode 100644
index 0000000000..47529e9c84
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/Player mine.redir
@@ -0,0 +1 @@
+B09.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/START.ogg b/Themes/_themekit-piu/Sounds/START.ogg
new file mode 100644
index 0000000000..35252e8a95
Binary files /dev/null and b/Themes/_themekit-piu/Sounds/START.ogg differ
diff --git a/Themes/_themekit-piu/Sounds/ScreenEvaluation start.redir b/Themes/_themekit-piu/Sounds/ScreenEvaluation start.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenEvaluation start.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic Options.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic Options.redir
new file mode 100644
index 0000000000..a3850946fe
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic Options.redir
@@ -0,0 +1 @@
+2-1.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic course music.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic course music.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic course music.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic difficulty easier.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic difficulty easier.redir
new file mode 100644
index 0000000000..cf2dcaddd7
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic difficulty easier.redir
@@ -0,0 +1 @@
+3-2.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic difficulty harder.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic difficulty harder.redir
new file mode 100644
index 0000000000..cf2dcaddd7
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic difficulty harder.redir
@@ -0,0 +1 @@
+3-2.ogg
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic locked.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic locked.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic locked.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic loop music.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic loop music.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic loop music.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic random music.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic random music.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic random music.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic roulette music.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic roulette music.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic roulette music.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic section music.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic section music.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic section music.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic sort music.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic sort music.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic sort music.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/Sounds/ScreenSelectMusic start.redir b/Themes/_themekit-piu/Sounds/ScreenSelectMusic start.redir
new file mode 100644
index 0000000000..1f8565ca21
--- /dev/null
+++ b/Themes/_themekit-piu/Sounds/ScreenSelectMusic start.redir
@@ -0,0 +1 @@
+_silent
\ No newline at end of file
diff --git a/Themes/_themekit-piu/ThemeInfo.ini b/Themes/_themekit-piu/ThemeInfo.ini
new file mode 100644
index 0000000000..9e5290bc2a
--- /dev/null
+++ b/Themes/_themekit-piu/ThemeInfo.ini
@@ -0,0 +1,3 @@
+[ThemeInfo]
+DisplayName=_Themekit_PIU
+Author=DaisuMaster
\ No newline at end of file
diff --git a/Themes/_themekit-piu/metrics.ini b/Themes/_themekit-piu/metrics.ini
new file mode 100644
index 0000000000..6dff88e5ef
--- /dev/null
+++ b/Themes/_themekit-piu/metrics.ini
@@ -0,0 +1,553 @@
+#Themekit PIU
+#Base para hacer Themes PIU
+#Indice
+
+#01# - System
+#02# - Pantallas
+#03# - Attract loop
+#04# - Gameplay loop
+#05# - Otras pantallas/debug
+
+;Nota: las anotaciones en los luas están en inglés porque se me dió la gana
+
+#00# - Antes de todo
+;[Global]
+;FallbackTheme=_themekit_piu
+
+#01# - System
+[ArrowEffects]
+;En PIU las flechas están separadas 60 pixeles
+ArrowSpacing=60
+
+[Background]
+;em, no
+ShowDancingCharacters=false
+;ala prex3 pc?
+UseStaticBackground=false
+
+[Common]
+;InitialScreen="ScreenInit"
+AutoSetStyle=true
+DefaultModifiers="1x"
+StepsTypesToHide="pump-couple,dance-double,dance-couple,dance-solo,dance-routine,lights-cabinet"
+;Si no se usa, no sé siquiera por qué los pongo así
+ColorP1Command=diffuse,color("#FFFFFF")
+ColorP2Command=diffuse,color("#FFFFFF")
+
+;ya no lo necesito
+[CodeDetector]
+PrevSteps1=""
+PrevSteps2=""
+NextSteps1=""
+NextSteps2=""
+
+;groups
+NextGroup=""
+PrevGroup=""
+
+;Sorting
+NextSort1=""
+NextSort2=""
+NextSort3=""
+NextSort4=""
+
+;Demases
+ModeMenu1=""
+ModeMenu2=""
+Mirror=""
+Left=""
+Right=""
+Shuffle=""
+SuperShuffle=""
+NextTransform=""
+NextScrollSpeed=""
+PreviousScrollSpeed=""
+NextAccel=""
+NextEffect=""
+NextAppearance=""
+NextTurn=""
+Reverse=""
+HoldNotes=""
+Mines=""
+Dark=""
+CancelAll=""
+NextTheme=""
+NextTheme2=""
+NextAnnouncer=""
+NextAnnouncer2=""
+NextBannerGroup=""
+NextBannerGroup2=""
+Hidden=""
+RandomVanish=""
+SaveScreenshot1=""
+SaveScreenshot2=""
+CancelAllPlayerOptions=""
+BackInEventMode=""
+
+[CustomDifficulty]
+;Screwy
+Names=""
+
+[CustomScoring]
+ComboAboveThresholdAddsToScoreBonus=0
+ComboMultiplier=0.0
+ComboScoreBonusThreshold=50
+ComboScoreBonusValue=+1000
+
+DoubleNoteScoreMultiplier=1.0
+TripleNoteScoreMultiplier=1.5
+QuadOrHigherNoteScoreMultiplier=2
+
+PointsW1=+1000
+PointsW2=+1000
+PointsW3=+500
+PointsW4=+100
+PointsW5=-200
+PointsMiss=-500
+PointsHitMine=-1000
+PointsCheckpointHit=+1000
+PointsCheckpointMiss=-200
+PointsNone=0
+PointsHoldHeld=+1000
+PointsHoldLetGo=-500
+
+[Gameplay]
+ComboIsPerRow=true
+MinScoreToContinueCombo="TapNoteScore_W3"
+MinScoreToMaintainCombo="TapNoteScore_W4"
+
+[GameState]
+GradeTierForExtra1="Grade_Tier03"
+GradeTierForExtra2="Grade_Tier03"
+MinDifficultyForExtra="Difficulty_Beginner"
+
+AreStagePlayerModsForced=false
+AreStageSongModsForced=false
+
+AllowExtra2=false
+LockExtraStageSelection=false
+
+[HoldJudgment]
+# no
+HoldJudgmentLetGoCommand=visible,false
+HoldJudgmentHeldCommand=visible,false
+
+[LifeMeterBar]
+;note scores
+;ADD
+LifePercentChangeCheckpointHit=0.008
+LifePercentChangeHeld=0.000
+LifePercentChangeW1=0.008
+LifePercentChangeW2=0.008
+LifePercentChangeW3=0.004
+;STAY
+LifePercentChangeW4=0.000
+LifePercentChangeLetGo=0.000
+;SUBSTRACT
+LifePercentChangeW5=-0.040
+LifePercentChangeMiss=-0.080
+LifePercentChangeCheckpointMiss=-0.080
+;mines
+LifePercentChangeHitMine=-0.160
+
+;no pierdes vida si presionas bads
+MinStayAlive="TapNoteScore_W5"
+;como no funciona de ese modo...
+LifeMultiplier=1.2
+
+;la mitad desde el inicio...
+InitialValue=0.5
+
+[MenuTimer]
+WarningStart=0
+WarningBeepStart=11
+
+Text1OnCommand=stopeffect;stoptweening;shadowlength,0;
+Text1FormatFunction=function(fSeconds) return string.format("%02i",fSeconds) end;
+Text2OnCommand=visible,false
+
+Warning0Command=
+
+[MusicWheel]
+SwitchSeconds=0.1
+ShowRoulette=false
+;probando cosas...
+;coverflowish
+ItemTransformFunction=function(self,offsetFromCenter,itemIndex,numItems) \
+ local x = offsetFromCenter * 250 \
+ if offsetFromCenter >= 1 then \
+ x = scale(offsetFromCenter+1,-1,1,-0.5,0.5) * 250 \
+ elseif offsetFromCenter <= -1 then \
+ x = scale(offsetFromCenter-1,-1,1,-0.5,0.5) * 250 \
+ end \
+ self:x( x ) \
+ self:z((-clamp(math.abs(offsetFromCenter),0,1)*250)-math.abs(offsetFromCenter)) \
+ self:rotationy( clamp( offsetFromCenter, -1, 1) * 90) \
+end;
+;7 items
+NumWheelItems=7
+;sólo dos por el momento, si ocupas más solo acomódalo en tu theme...
+SortOrders={ "SortOrder_Group", "SortOrder_Genre" }
+
+;limpio de toda impureza... quiero discs en mi musicwheel :3
+[MusicWheelItem]
+SongNameOnCommand=zoom,0
+CourseOnCommand=zoom,0
+SectionExpandedOnCommand=zoom,0
+SectionCollapsedOnCommand=zoom,0
+SectionCountOnCommand=zoom,0
+RouletteOnCommand=zoom,0
+SortOnCommand=zoom,0
+ModeOnCommand=zoom,0
+GradesShowMachine=false
+
+[Player]
+ReceptorArrowsYStandard=-173
+ReceptorArrowsYReverse=173
+DrawDistanceBeforeTargetsPixels=SCREEN_HEIGHT
+DrawDistanceAfterTargetsPixels=-100
+
+JudgeHoldNotesOnSameRowTogether=false
+HoldCheckpoints=true
+CheckpointsUseTimeSignatures=true
+CheckpointsTapsSeparateJudgment=false
+CheckpointsFlashOnHold=true
+ImmediateHoldLetGo=false
+RequireStepOnHoldHeads=false
+InitialHoldLife=1
+MaxHoldLife=1
+RollBodyIncrementsCombo=false
+ScoreMissedHoldsAndRolls=false
+
+;Grades
+[PlayerStageStats]
+NumGradeTiersUsed=7
+;S
+GradePercentTier01=1
+;S
+GradePercentTier02=1
+;A
+GradePercentTier03=0.8
+;B
+GradePercentTier04=0.6
+;C
+GradePercentTier05=0.4
+;D
+GradePercentTier06=0.2
+;F
+GradePercentTier07=-999999
+;FPC = SS
+GradeTier01IsAllW2s=true
+GradeTier02IsAllW2s=false
+;FC = S
+GradeTier02IsFullCombo=true
+
+[SongManager]
+ExtraColorMeter=17
+ExtraStage2DifficultyMax=999
+NumSongGroupColors=1
+SongGroupColor1=color("#ffffff")
+
+#02# - Pantallas
+[Screen]
+ShowCreditDisplay=true
+
+[ScreenOptionsMaster]
+SongMenu="7"
+SongMenuDefault=""
+SongMenu,1="name,Speed;screen,Speed"
+SongMenu,2="name,Noteskins;screen,Noteskins"
+SongMenu,3="name,FadeNotes;screen,FadeNotes"
+SongMenu,4="name,Scroll;screen,Scroll"
+SongMenu,5="name,Effect;screen,Effect"
+SongMenu,6="name,Receptor;screen,Receptor"
+SongMenu,7="name,ResetOptions"
+
+Speed="10"
+SpeedDefault="mod,1x,no randomspeed"
+Speed,1="mod,0.5x;name,0.5x"
+Speed,2="mod,1x;name,1x"
+Speed,3="mod,1.5x;name,1.5x"
+Speed,4="mod,2x;name,2x"
+Speed,5="mod,3x;name,3x"
+Speed,6="mod,4x;name,4x"
+Speed,7="mod,5x;name,5x"
+Speed,8="mod,6x;name,6x"
+Speed,9="mod,7x;name,7x"
+Speed,10="mod,8x;name,8x"
+
+FadeNotes="5;selectmultiple"
+FadeNotesDefault="mod,no hidden,no sudden,no stealth,no blink"
+FadeNotes,1="name,Vanish;mod,hidden"
+FadeNotes,2="name,RndVanish;mod,randomvanish"
+FadeNotes,3="name,Appear;mod,sudden"
+FadeNotes,4="name,Nonstep;mod,stealth"
+FadeNotes,5="name,Flash;mod,blink"
+
+Scroll="5;selectmultiple"
+ScrollDefault="mod,no boost,no brake,no wave,no expand,no xmode"
+Scroll,1="name,Accel;mod,boost"
+Scroll,2="name,Decel;mod,brake"
+Scroll,3="name,Worm;mod,expand"
+Scroll,4="name,Wave;mod,wave"
+Scroll,5="name,XMode;mod,xmode"
+
+Effect="6;selectmultiple"
+EffectDefault="mod,no dizzy,no tornado,no drunk,no beat,no tiny,no bumpy"
+Effect,1="name,Spin;mod,628% dizzy"
+Effect,2="name,Snake;mod,25% tornado"
+Effect,3="name,Drift;mod,drunk"
+Effect,4="name,Beat;mod,beat"
+Effect,5="name,Shrink;mod,tiny"
+Effect,6="name,Jumps;mod,bumpy"
+
+Receptor="5;selectmultiple"
+ReceptorDefault="mod,no dark,no reverse,no centered"
+Receptor,1="name,Freedom;mod,dark"
+Receptor,2="name,Reverse;mod,reverse"
+Receptor,3="name,Center;mod,centered"
+Receptor,4="name,Flip;mod flip"
+Receptor,5="name,Invert,mod, invert"
+
+[ScreenPlayerOptions]
+;LineNames="1,2,3,4,5,6,7,8,14"
+LineNames="1,8"
+;Line1="lua,SpeedMods()"
+Line1="list,Speed"
+
+[ScreenWithMenuElements]
+TimerX=SCREEN_CENTER_X
+TimerY=10
+TimerOnCommand=
+TimerOffCommand=
+
+#03# - Attract loop
+[ScreenInit]
+PlayMusic=true
+
+#04# - Gameplay loop
+
+;82w
+[ScreenTitleMenu]
+;Next, Prev y CoinChange Screen
+PrevScreen="ScreenInit"
+NextScreen="ScreenTitleMenu"
+CoinModeChangeScreen="ScreenTitleMenu"
+
+;choices
+ChoiceNames="1,2,3,5"
+Choice1="text,Play;applydefaultoptions;difficulty,beginner;screen,ScreenProfileLoad"
+;ScreenProfileLoad"
+Choice2="text,Options;screen,ScreenOptionsService"
+Choice3="text,Editor;screen,ScreenOptionsEdit"
+Choice4="text,Test;screen,ScreenTest"
+Choice5="text,Exit;screen,ScreenExit"
+
+;el scroller
+LoopScroller=true
+WrapScroller=true
+ScrollerSecondsPerItem=0.1
+ScrollerNumItemsToDraw=5
+
+ScrollerX=SCREEN_CENTER_X
+ScrollerY=SCREEN_CENTER_Y
+ScrollerTransform=function(self,offset,itemIndex,numItems) self:x(offset * 200); end
+
+[ScreenProfileLoad]
+NextScreen="ScreenSelectMusic"
+PrevScreen="ScreenTitleMenu"
+
+;099
+[ScreenSelectMusic]
+;settings
+NextScreen="ScreenStageInformation"
+PrevScreen="ScreenProfileSave"
+;"ScreenTitleMenu"
+;mucho tiempo, aprovéchalo
+TimerSeconds=100
+;no
+ShowOptionsMessageSeconds=0
+;em
+ScreenModsCommand=
+;si, eso
+DefaultSort="Group"
+;¡No!
+DoRouletteOnMenuTimer=false
+
+;plz
+SampleMusicLoops=false
+SampleMusicDelay=0.5
+SampleMusicDelayInit=1.5
+;1: oye, esto para qué es?
+;2: ez - no - hd - cz - fs - nm - ez - no - hd - cz - fs - nm - ez
+;1: ok ok, ya entendí...
+WrapChangeSteps=true
+;un pequeño agregado mío...
+ChangeStepsWithGameButtons=true
+PreviousDifficultyButton="MenuUp"
+NextDifficultyButton="MenuDown"
+########################
+# Custom code detector #
+########################
+CodeNames=GetUserPrefB("OptionsMode") and "Summon" or "Noteskin,Speed,Cancel,Hidden,SuperShuffle,XMode,Left,Dark,GradeReverse"
+;main codes
+CodeNoteskin="UpLeft,Center,UpRight,Center"
+CodeSpeed="UpLeft,UpRight,UpLeft,UpRight,Center"
+CodeCancel="DownLeft,DownRight,DownLeft,DownRight,DownLeft,DownRight"
+;secondary codes
+CodeHidden="UpLeft,UpRight,DownLeft,DownRight,Center"
+CodeSuperShuffle="UpLeft,UpRight,UpLeft,UpRight,DownLeft,DownRight,DownLeft,DownRight,Center"
+CodeXMode="DownLeft,UpRight,DownLeft,UpRight,DownRight,UpLeft,DownRight,UpLeft,Center"
+CodeLeft="DownRight,DownLeft,UpRight,UpLeft,DownRight,DownLeft,UpRight,UpLeft,Center"
+CodeDark="UpLeft,DownLeft,UpRight,DownRight,DownRight,UpLeft,UpRight,DownLeft,Center"
+;tertiary codes
+CodeGradeReverse="UpLeft,UpRight,Center,DownLeft,DownRight,DownRight,DownLeft,Center,UpRight,UpLeft,Center"
+CodeSomething="Select,Select,Select,Select,Center"
+
+;special cases or whatever...
+CodeSummon="DownLeft,DownRight,DownLeft,DownRight,DownLeft,DownRight"
+
+;confirm
+TwoPartSelection=true
+TwoPartConfirmsOnly=true
+
+;oplist
+;UseOptionsList=true
+
+;otros elementos
+TimerOnCommand=visible,false
+BannerOnCommand=visible,false
+MusicWheelX=SCREEN_CENTER_X
+MusicWheelY=SCREEN_CENTER_Y
+MusicWheelOnCommand=SetDrawByZPosition,true;fov,90
+
+CDTitleOnCommand=visible,false;pause;
+
+[ScreenCustomOptionsList]
+;with this selectmusic preview still plays when stacking this screen
+PlayMusic=false
+
+Class="ScreenSplash"
+Fallback="ScreenSplash"
+NextScreen="ScreenSelectMusic"
+PrevScreen="ScreenSelectMusic"
+
+CodeNames="Prev,Next,Toggle,Back1=Back,Back2=Back"
+CodePrev="+DownLeft"
+CodeNext="+DownRight"
+CodeToggle="Center"
+CodeBack1="UpLeft"
+CodeBack2="UpRight"
+
+;pnz showoff
+[ScreenStageInformation]
+TimerSeconds=1
+TimerOnCommand=visible,false
+NextScreen="ScreenGameplay"
+PrevScreen="ScreenSelectMusic"
+PrepareScreen="ScreenGameplay"
+ShowCreditDisplay=false
+
+;00
+;in before iguana play...
+[ScreenGameplay]
+NextScreen=GameplayNext()
+PrevScreen="ScreenSelectMusic"
+
+FailOnMissCombo=StageBreak()
+
+MinSecondsToStep=0.5
+MinSecondsToMusic=0
+MusicFadeOutSeconds=1
+
+;con toda confianza puedo decir: la (barra de) vida es una mierda XD
+LifeP1OnCommand=visible,false
+LifeP2OnCommand=visible,false
+ScoreP1OnCommand=visible,false
+ScoreP2OnCommand=visible,false
+
+PlayerInitCommand=y,240;zoom,(THEME:GetMetric("Common","ScreenHeight")/480)
+StartGivesUp=false
+BackGivesUp=false
+
+;uh...
+PlayerP1OnePlayerOneSideX=SCREEN_CENTER_X-160
+PlayerP2OnePlayerOneSideX=SCREEN_CENTER_X+160
+PlayerP1TwoPlayersTwoSidesX=SCREEN_CENTER_X-160
+PlayerP2TwoPlayersTwoSidesX=SCREEN_CENTER_X+160
+PlayerP1OnePlayerTwoSidesX=SCREEN_CENTER_X
+PlayerP2OnePlayerTwoSidesX=SCREEN_CENTER_X
+PlayerP1TwoPlayersSharedSidesX=SCREEN_CENTER_X
+PlayerP2TwoPlayersSharedSidesX=SCREEN_CENTER_X
+
+;Si no pones estos, el extra stage te crashea si le das back...
+SurviveTimeX=0
+SurviveTimeY=0
+SurviveTimeOnCommand=visible,false
+SurviveTimeOffCommand=
+
+;83
+[ScreenEvaluationNormal]
+ForceTimer=true
+TimerSeconds=10
+TimerMetricsGroup="MenuTimerNoSound"
+;TimerOnCommand=visible,false
+NextScreen=EvaluationNext()
+
+;LT%02d
+[ScreenNextStage]
+Class="ScreenSplash"
+Fallback="ScreenSplash"
+PrevScreen="ScreenSelectMusic"
+NextScreen="ScreenSelectMusic"
+
+ForceTimer=true
+TimerSeconds=3
+TimerMetricsGroup="MenuTimerNoSound"
+TimerOnCommand=visible,false
+
+;083
+[ScreenStageBreak]
+Class="ScreenSplash"
+Fallback="ScreenSplash"
+PrevScreen=StageBreakNext()
+NextScreen=StageBreakNext()
+ForceTimer=true
+TimerSeconds=5
+TimerMetricsGroup="MenuTimerNoSound"
+TimerOnCommand=visible,false
+
+;guardar perfiles
+[ScreenProfileSave]
+NextScreen="ScreenGameOver"
+PrevScreen="ScreenGameOver"
+
+;84
+[ScreenGameOver]
+Class="ScreenSplash"
+Fallback="ScreenSplash"
+PrevScreen=GameOverNext()
+NextScreen=GameOverNext()
+
+PlayMusic=true
+ForceTimer=true
+TimerSeconds=5
+TimerMetricsGroup="MenuTimerNoSound"
+TimerOnCommand=visible,false
+
+#05# - Otras pantallas/debug
+[ScreenOptionsTheme]
+Fallback="ScreenOptionsServiceChild"
+LineNames="1"
+Line1="lua,UserPrefOptionsMode()"
+
+;derivadas de screenoptions
+;Sí porque faltan lineas en varias y otras te llevan a pantallas que no quiero...
+[ScreenOptionsService]
+PrevScreen="ScreenTitleMenu"
+;LineNames="SD,1,2,13,3,10,11,4,12,6,5,8,9"
+
+[ScreenOptionsSystemDirection]
+Fallback="ScreenOptionsServiceChild"
+PrevScreen="ScreenOptionsService"
+NextScreen="ScreenOptionsService"
\ No newline at end of file
diff --git a/Themes/_themekit-piu/reads.txt b/Themes/_themekit-piu/reads.txt
new file mode 100644
index 0000000000..a1a10a8b4a
--- /dev/null
+++ b/Themes/_themekit-piu/reads.txt
@@ -0,0 +1,53 @@
+Congrats, you're reading the readme
+
+-= Themekit piu: a base for piu themes =-
+Use this theme as fallback for your own themes so you don't need to deal with
+piu related metric setups like lifebars, tiers, effects and such; also some
+screens are already linked (no attract screens tough)
+
+-= Why you do this? =-
+Well, I'm a PIU player, and as one, I like to have PIU setups in my Stepmania themes
+
+-= Basics and how to =-
+Easy!
+ Put this under /Themes
+ Make a blank folder under /Themes with whatever name you want for your theme
+ Create a blank Metrics.ini file inside
+ Open it
+ Write in:
+
+
+[Global]
+FallbackTheme=_themekit_piu
+
+
+ And there you go! just mount the screens that you want to work with or
+add/replace metrics/elements
+
+-= FAQ and details =-
+Q: Can't select themekit
+A: Themekits aren't supposed to be selectable, but if you want to use this as a
+theme (wich actually works like one) remove the first underscore in the theme
+folder name; alternately you can make a blank theme and fallback it with this
+(explained up there^) and it should work as is.
+
+Q: Theme doesn't work.
+A: Maybe you're using stepmania 4 alpha or some old cvs build, use sm-ssc
+
+Q: I want to use (partial or entirely) the lua modules outside
+A: Go ahead, just please read the notes if there are any.
+
+Q: Help me with X
+A: Sorry, I don't feel like doing so...
+
+Q: I want to contact you
+A: I don't like to have my email address floating around, visit sm-ssc irc channel
+at irc.badnik.net/sm-ssc, I'll be usually there
+
+Q: Er... Your real name?
+A: yeah, Alberto Ramos
+
+-= Least but not least: Final notes =-
+Well, I think that's pretty much it and what you need to know about this themekit,
+I hope that you enjoy it, whenever you are or not a themer, and if you are one I
+just hope that I didn't wasted time doing this... er... you found this useful ^^
\ No newline at end of file
diff --git a/Themes/themekit/BGAnimations/ScreenTitleMenu underlay.lua b/Themes/themekit/BGAnimations/ScreenTitleMenu underlay.lua
new file mode 100644
index 0000000000..1646b07202
--- /dev/null
+++ b/Themes/themekit/BGAnimations/ScreenTitleMenu underlay.lua
@@ -0,0 +1,7 @@
+-- This adds the logo man~
+InitUserPrefs();
+local t = Def.ActorFrame {};
+
+t[#t+1] = StandardDecorationFromFileOptional("Logo","Logo");
+
+return t
\ No newline at end of file
diff --git a/Themes/themekit/BGAnimations/ScreenWithMenuElements background/VOL1-29-NTSC.mpg b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/VOL1-29-NTSC.mpg
new file mode 100644
index 0000000000..6f579ea520
Binary files /dev/null and b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/VOL1-29-NTSC.mpg differ
diff --git a/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_16 (stretch).png b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_16 (stretch).png
new file mode 100644
index 0000000000..eda8b07a4b
Binary files /dev/null and b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_16 (stretch).png differ
diff --git a/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_32 (stretch).png b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_32 (stretch).png
new file mode 100644
index 0000000000..ee4d071b3d
Binary files /dev/null and b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_32 (stretch).png differ
diff --git a/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_8 (stretch).png b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_8 (stretch).png
new file mode 100644
index 0000000000..e078062a7d
Binary files /dev/null and b/Themes/themekit/BGAnimations/ScreenWithMenuElements background/_8 (stretch).png differ
diff --git a/Themes/themekit/BGAnimations/ScreenWithMenuElements decorations/default.lua b/Themes/themekit/BGAnimations/ScreenWithMenuElements decorations.lua
similarity index 100%
rename from Themes/themekit/BGAnimations/ScreenWithMenuElements decorations/default.lua
rename to Themes/themekit/BGAnimations/ScreenWithMenuElements decorations.lua
diff --git a/Themes/themekit/Graphics/MusicWheelItem Song ColorPart.lua b/Themes/themekit/Graphics/MusicWheelItem Song ColorPart.lua
new file mode 100644
index 0000000000..edfa6611f8
--- /dev/null
+++ b/Themes/themekit/Graphics/MusicWheelItem Song ColorPart.lua
@@ -0,0 +1,14 @@
+return Def.ActorFrame {
+ Def.Quad {
+ InitCommand=cmd(x,-128+4;zoomto,4,46);
+-- OnCommand=cmd(diffuse,color("0,0,0,0.5"));
+ };
+--[[ Def.Quad {
+ InitCommand=cmd(x,-128+16+6;zoomto,32,46);
+-- OnCommand=cmd(faderight,1;diffusealpha,0.5);
+ }; --]]
+--[[ Def.Quad {
+ InitCommand=cmd(x,2;y,23;zoomto,320,1);
+-- OnCommand=cmd(diffuse,color("0,0,0,0.5"));
+ }; --]]
+};
\ No newline at end of file
diff --git a/Themes/themekit/Graphics/MusicWheelItem Song NormalPart.lua b/Themes/themekit/Graphics/MusicWheelItem Song NormalPart.lua
new file mode 100644
index 0000000000..60de25400c
--- /dev/null
+++ b/Themes/themekit/Graphics/MusicWheelItem Song NormalPart.lua
@@ -0,0 +1,6 @@
+return Def.ActorFrame {
+ Def.Quad {
+ InitCommand=cmd(x,4;zoomto,256-4,46);
+ OnCommand=cmd(diffuse,color("0,0,0,0.5"));
+ };
+};
\ No newline at end of file
diff --git a/Themes/themekit/Graphics/ScreenTitleMenu Logo.png b/Themes/themekit/Graphics/ScreenTitleMenu Logo.png
new file mode 100644
index 0000000000..15e8583c76
Binary files /dev/null and b/Themes/themekit/Graphics/ScreenTitleMenu Logo.png differ
diff --git a/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua b/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua
index fa40c9c589..437e80dd9c 100644
--- a/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua
+++ b/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua
@@ -3,9 +3,13 @@ local gc = Var("GameCommand");
local t = Def.ActorFrame {};
t[#t+1] = LoadFont("Common Normal") .. {
+ Name="Text";
Text=gc:GetText();
};
-t.GainFocusCommand=cmd(diffusealpha,1);
-t.LoseFocusCommand=cmd(diffusealpha,0.5);
+t[1].OnCommand=Screen.Metric("ScrollerItemOnCommand");
+t[1].GainFocusCommand=Screen.Metric("ScrollerItemGainFocusCommand");
+t[1].LoseFocusCommand=Screen.Metric("ScrollerItemLoseFocusCommand");
+t[1].OffFocusedCommand=Screen.Metric("ScrollerItemOffFocusedCommand");
+t[1].OffUnfocusedCommand=Screen.Metric("ScrollerItemOffUnfocusedCommand");
return t;
\ No newline at end of file
diff --git a/Themes/themekit/Graphics/ScreenWithMenuElements Footer.png b/Themes/themekit/Graphics/ScreenWithMenuElements Footer.png
new file mode 100644
index 0000000000..eabccf5713
Binary files /dev/null and b/Themes/themekit/Graphics/ScreenWithMenuElements Footer.png differ
diff --git a/Themes/themekit/Graphics/ScreenWithMenuElements Header.png b/Themes/themekit/Graphics/ScreenWithMenuElements Header.png
new file mode 100644
index 0000000000..b1ffdc490e
Binary files /dev/null and b/Themes/themekit/Graphics/ScreenWithMenuElements Header.png differ
diff --git a/Themes/themekit/Sounds/_Music menu.redir b/Themes/themekit/Sounds/_Music menu.redir
new file mode 100644
index 0000000000..c29cb1da10
--- /dev/null
+++ b/Themes/themekit/Sounds/_Music menu.redir
@@ -0,0 +1 @@
+_Music title
\ No newline at end of file
diff --git a/Themes/themekit/Sounds/_Music title (loop).ogg b/Themes/themekit/Sounds/_Music title (loop).ogg
new file mode 100644
index 0000000000..d1ff738f07
Binary files /dev/null and b/Themes/themekit/Sounds/_Music title (loop).ogg differ
diff --git a/Themes/themekit/Sounds/_Music title (loop).sm b/Themes/themekit/Sounds/_Music title (loop).sm
new file mode 100644
index 0000000000..283865a6c9
--- /dev/null
+++ b/Themes/themekit/Sounds/_Music title (loop).sm
@@ -0,0 +1,5 @@
+#TITLE:Break The Sabbath;
+#OFFSET:0.000;
+#BPMS:0.000=140.000;
+#STOPS:;
+
diff --git a/Themes/themekit/_Resources/ScreenTitleMenu logo.psd b/Themes/themekit/_Resources/ScreenTitleMenu logo.psd
new file mode 100644
index 0000000000..79fb479580
Binary files /dev/null and b/Themes/themekit/_Resources/ScreenTitleMenu logo.psd differ
diff --git a/Themes/themekit/_Resources/ScreenWithMenuElements Footer.psd b/Themes/themekit/_Resources/ScreenWithMenuElements Footer.psd
new file mode 100644
index 0000000000..8120704912
Binary files /dev/null and b/Themes/themekit/_Resources/ScreenWithMenuElements Footer.psd differ
diff --git a/Themes/themekit/_Resources/ScreenWithMenuElements Header.psd b/Themes/themekit/_Resources/ScreenWithMenuElements Header.psd
new file mode 100644
index 0000000000..d874523b70
Binary files /dev/null and b/Themes/themekit/_Resources/ScreenWithMenuElements Header.psd differ
diff --git a/Themes/themekit/_library.txt b/Themes/themekit/_library.txt
new file mode 100644
index 0000000000..1b6b60c1e1
--- /dev/null
+++ b/Themes/themekit/_library.txt
@@ -0,0 +1,11 @@
+===
+COLORS
+====
+ BACKGROUND
+====
+ Clear #000000 (Black)
+ Light #646464 (Grey)
+ Primary #007cd4 (Slate Blue)
+ Secondary #a4005d (Slate Purple)
+ the base is black (#000000)
+===
\ No newline at end of file
diff --git a/Themes/themekit/_todo.txt b/Themes/themekit/_todo.txt
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Themes/themekit/metrics.ini b/Themes/themekit/metrics.ini
index fbc0f5651a..12f3920d82 100644
--- a/Themes/themekit/metrics.ini
+++ b/Themes/themekit/metrics.ini
@@ -4,13 +4,13 @@ FallbackTheme=_fallback
ShowHeader=true
HeaderX=SCREEN_CENTER_X
HeaderY=SCREEN_TOP
-HeaderOnCommand=
+HeaderOnCommand=vertalign,top
HeaderOffCommand=
#
ShowFooter=true
FooterX=SCREEN_CENTER_X
FooterY=SCREEN_BOTTOM
-FooterOnCommand=
+FooterOnCommand=vertalign,bottom
FooterOffCommand=
#
TimerX=SCREEN_WIDTH-64
@@ -27,8 +27,30 @@ FrameOnCommand=
# Warning
Warning10Command=diffuseshift;effectperiod,1;effectcolor2,Color("Red");effectcolor1,color("0.5,0,0,1");
[ScreenTitleMenu]
-ShowHeader=true
-ShowFooter=true
+# Don't show these
+ShowHeader=false
+ShowFooter=false
+# Logo
+ShowLogo=true
+LogoX=SCREEN_CENTER_X
+LogoY=SCREEN_CENTER_Y-48
+LogoOnCommand=zoom,1;
+LogoOffCommand=zoom,0;
+# Title Menu
+ScrollerX=SCREEN_CENTER_X
+ScrollerY=SCREEN_CENTER_Y+96
+ScrollerOnCommand=
+ScrollerOffCommand=
+# Menu Items [ThemeKit Only]
+ScrollerItemOnCommand=shadowlength,1;strokecolor,color("0,0,0,0.25");
+# GainFocus is when an item is selected.
+ScrollerItemGainFocusCommand=stoptweening;linear,0.125;zoom,1;
+# LoseFocus is when an item is deselected.
+ScrollerItemLoseFocusCommand=stoptweening;linear,0.125;zoom,0.75;
+# OffFocused is for items you have selected and the screen is exiting.
+ScrollerItemOffFocusedCommand=sleep,0.35;linear,0.15;zoom,0;
+# OffUnfocused is for items that were not selected and the screen is exiting.
+ScrollerItemOffUnfocusedCommand=linear,0.15;zoom,0;
[ScreenSelectMusic]
MusicWheelX=SCREEN_RIGHT-128-18
MusicWheelOnCommand=draworder,-1