-- Custom Speed Mods v1.4 -- by AJ Kelly of KKI Labs -- http://kki.ajworld.net/ --[[ changelog: v1.4 * Try to auto-set the speed mod to 1.0 if: 1) The player hasn't already chosen a speed mod 2) The player's custom speed mod collection starts with a value under 1x. Due to the way the custom speed mods are coded, it will always pick the first value, even if it's not 1.0x. v1.3 * strip whitespace out of file in case people use it. (I don't think it really works but SM seems to think the mods are legal) * fixed an error related to using the fallback return value. v1.2 * small fixes * more comments v1.1 * Cleaned up code some, I think. ]] -- This code allows end users to add their own speed mods to the list. -- Caveats: -- * Still unsure if this will work if the theme is installed as a package. function SpeedMods() -- GetSpeedMods() - read all the speed mods from a file. local function GetSpeedMods() local s = { }; local file = RageFileUtil.CreateRageFile(); -- the file is located at Data/SpeedMods.txt, meaning any other theme -- that reads custom speed mods in this location will use them. -- the root is the StepMania install directory. -- Currently unknown if you can get this to read from a memory card -- profile directory, much less a local profile directory. -- If you use Portable StepMania alpha 4+, you should be fine. local path = "Data/SpeedMods.txt" if file:Open(path, 1) then -- add each mod to the table. split by a comma. local a = file:Read(); s = split(',',a); -- whitespace stripping -- I'm hoping this works for all spaces for i=1,#s do string.gsub(s[i], "%s", ""); end file:destroy(); return s; else -- couldn't be read for whatever reasons; write & return fallback Trace("[CustomSpeedMods]: Could not read SpeedMods; writing out fallback!"); file:Open(path, 2); file:Write("0.5x,1x,1.5x,2x,3x,4x,8x,C200,C400"); file:destroy(); return {"0.5x","1x","1.5x","2x","3x","4x","8x","C200","C400"}; end; -- this is unlikely but I am coding defensively Trace("[CustomSpeedMods]: unexpected jump location; using fallback!"); return {"0.5x","1x","1.5x","2x","3x","4x","8x","C200","C400"}; end; -- here we see the option menu itself. local t = { Name = "Speed", LayoutType = "ShowAllInRow", SelectType = "SelectOne", OneChoiceForAllPlayers = false, ExportOnChange = false, Choices = GetSpeedMods(), LoadSelections = function(self, list, pn) local pMods = GAMESTATE:GetPlayerState(pn):GetPlayerOptions("ModsLevel_Preferred"); for i = 1,table.getn(self.Choices) do if string.find(pMods, self.Choices[i]) then list[i] = true; return; end; end; -- if we've reached this point, try to find 1x or 1.0x instead. for i = 1,table.getn(self.Choices) do if self.Choices[i] == "1x" or self.Choices[i] == "1.0x" then list[i] = true; return end; end; end, SaveSelections = function(self, list, pn) for i = 1,table.getn(self.Choices) do if list[i] then local PlayerState = GAMESTATE:GetPlayerState(pn); PlayerState:SetPlayerOptions("ModsLevel_Preferred",self.Choices[i]); return end end end }; setmetatable( t, t ); return t; end; --[[ Copyright © 2008 AJ Kelly/KKI Labs Use freely. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ]]