diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3ca08a3..cc1acd2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,23 @@ jobs: with: path: randomiser + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.7 + + - uses: actions/cache@v4 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-pip-a + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install python dependencies + run: | + python -m pip install --upgrade pip + pip install pygit2 + - name: Check mod launcher version id: mod-launcher-version run: | @@ -49,6 +66,12 @@ jobs: run: | Expand-Archive -LiteralPath '.\launcher.zip' -DestinationPath '.\mod-launcher' + - name: Upgrade Meta.ini + run: | + cd randomiser\Randomiser + python meta.py + del meta.py + - name: Compile mod run: | & '.\mod-launcher\Lucas Simpsons Hit & Run Mod Launcher.exe' -ignoreloaderrors -mods ".\randomiser" -compile "Randomiser" -outputpath ".\" | Out-String diff --git a/Randomiser/CustomFiles.ini b/Randomiser/CustomFiles.ini index 49b1f4f..60428a8 100644 --- a/Randomiser/CustomFiles.ini +++ b/Randomiser/CustomFiles.ini @@ -24,6 +24,7 @@ art/missions/*_doors.p3d=Resources/HandleLevelDoors.lua *.rms=Resources/HandleRMS.lua art/cars/*.p3d=Resources/HandleCarModel.lua art/frontend/scrooby/frontend.p3d=Resources/HandleFrontend.lua +art/frontend/scrooby/ingame.p3d=Resources/HandleIngame.lua art/frontend/dynaload/images/license/licensePC.p3d=Resources/RandomLicense.lua scripts/cars/*.con=Resources/HandleCar.lua art/l*i*.p3d=Resources/HandleLevelInterior.lua diff --git a/Randomiser/CustomFiles.lua b/Randomiser/CustomFiles.lua index 17c1baf..65f553d 100644 --- a/Randomiser/CustomFiles.lua +++ b/Randomiser/CustomFiles.lua @@ -9,6 +9,7 @@ dofile(Paths.Resources .. "GlobalVariables.lua") dofile(Paths.Resources .. "GlobalFunctions.lua") dofile(Paths.Resources .. "lib/P3D.lua") dofile(Paths.Resources .. "lib/P3DFunctions.lua") +dofile(Paths.Resources .. "lib/Seed.lua") GetFiles(RandomCharP3DPool, "/GameData/art/chars/", {".p3d"}) local ExcludedChars = {["npd_m"]=true,["ndr_m"]=true,["nps_m"]=true} @@ -50,9 +51,9 @@ if Settings.SpeedrunMode then DebugPrint("Speedrun mode enabled, settings have been overridden") end -dofile(Paths.Resources .. "MissionScripts/LoadModules.lua") - -Cache = {} +if Settings.IsSeeded then + Seed.Init() +end if Settings.UseDebugSettings then if not Confirm("You have Use Debug Settings enabled. This allows a secondary mod to force certain randomisations and sometimes run code.\nAre you sure you want this enabled?") then @@ -64,20 +65,6 @@ end DebugPrint("Debug settings enabled: " .. (Settings.UseDebugSettings and "true" or "false")) -if #RandomCarPoolPlayer < 5 and Settings.RandomPlayerVehicles then - Alert("You have chosen less than 5 cars for the random player pool. You must choose at least 5 cars.") - os.exit() -elseif #RandomCarPoolTraffic < 5 and Settings.RandomTraffic then - Alert("You have chosen less than 5 cars for the random traffic pool. You must choose at least 5 cars.") - os.exit() -elseif #RandomCarPoolMission < 5 and Settings.RandomMissionVehicles then - Alert("You have chosen less than 5 cars for the random mission pool. You must choose at least 5 cars.") - os.exit() -elseif #RandomCarPoolChase < 5 and Settings.RandomChase then - Alert("You have chosen less than 5 cars for the random chase pool. You must choose at least 5 cars.") - os.exit() -end - if Settings.VerboseDebug then local OldOutput = Output local OldRedirect = Redirect @@ -112,9 +99,32 @@ if Settings.RandomDialogue then dofile(Paths.Resources .. "RandomDialogue.lua") end +if #RandomCarPoolPlayer < 5 and Settings.RandomPlayerVehicles then + Alert("You have chosen less than 5 cars for the random player pool. You must choose at least 5 cars.") + os.exit() +elseif #RandomCarPoolTraffic < 5 and Settings.RandomTraffic then + Alert("You have chosen less than 5 cars for the random traffic pool. You must choose at least 5 cars.") + os.exit() +elseif #RandomCarPoolMission < 5 and Settings.RandomMissionVehicles then + Alert("You have chosen less than 5 cars for the random mission pool. You must choose at least 5 cars.") + os.exit() +elseif #RandomCarPoolChase < 5 and Settings.RandomChase then + Alert("You have chosen less than 5 cars for the random chase pool. You must choose at least 5 cars.") + os.exit() +end + DebugPrint("Loaded " .. #RandomCarPoolPlayer .. " cars for the random Player pool") DebugPrint("Loaded " .. #RandomCarPoolTraffic .. " cars for the random Traffic pool") DebugPrint("Loaded " .. #RandomCarPoolMission .. " cars for the random Mission pool") DebugPrint("Loaded " .. #RandomCarPoolChase .. " cars for the random Chase pool") DebugPrint("Using " .. RandomPedPoolN .. " pedestrians") -DebugPrint("Using " .. #RandomCharP3DPool .. " characters") \ No newline at end of file +DebugPrint("Using " .. #RandomCharP3DPool .. " characters") + +dofile(Paths.Resources .. "MissionScripts/LoadModules.lua") + +-- Seed.NonModuleSeed +if Settings.IsSeeded then + Seed.PrintSpoiler() +end +Cache = {} + diff --git a/Randomiser/Meta.ini b/Randomiser/Meta.ini index 46fb9fb..cdb7ac0 100644 --- a/Randomiser/Meta.ini +++ b/Randomiser/Meta.ini @@ -12,7 +12,7 @@ RequiredHack=FileSystemRCFs OptionalFramework=RandomiserDialogue OptionalFramework=RandomiserCars OptionalFramework=RandomiserChars -Version=2.1-git +Version=3.0-git SettingsHeight=601 SettingsWidth=550 RequiredLauncher=1.24 @@ -84,6 +84,90 @@ Name=Steve Credits=1 Group=Testing +[Setting] +Name=SpeedrunMode +Title=Speedrun Mode +Type=TickBox +Default=0 +Tooltip=Enables the speedrun settings viable for the leaderboards +Page=General +Group=Rulesets + +[Setting] +Name=IsSeeded +Title=Seeded Mode +Type=TickBox +Default=0 +Tooltip=Enables seeded mode for predictable randomness +Page=General +Group=Seedng + +[Setting] +Name=Seed +Title=Seed +Type=Text +Default= +Tooltip=Seed to use for RNG, technically a base64 encoded 64-bit integer but short words work too. If blank a new seed is generated +Page=General +Group=Seedng + +[Setting] +Name=SkipLocks +Title=Remove car/costume requirements +Type=TickBox +Default=0 +Tooltip=Remove specific car/costume requirements from certain missions +Page=General +Group=Gameplay + +[Setting] +Name=SkipFMVs +Title=Skip cutscenes (except intro cutscene) +Type=TickBox +Default=0 +Tooltip=Remove all in-game cutscenes, including the ones at the end of levels. The intro cutscene can be skipped by enabling "No Introduction Movies" +Page=General +Group=Gameplay + +[Setting] +Name=BoostHP +Title=Increase HP for weak cars +Type=TickBox +Default=0 +Tooltip=Slightly increases HP for weak vehicles like the rocket car +Page=General +Group=Gameplay + +[Setting] +Name=DebugLevel +Title=Debug level +Type=Number +Integer=1 +Min=0 +Max=5 +Default=0 +Tooltip=Sets the debug level for console printing - 0 will print only the basics whilst 5 will print everything +Page=General +Group=Debugging + +[Setting] +Name=VerboseDebug +Title=Verbose debug +Type=TickBox +Default=0 +Tooltip=If enabled, outputs all modified files to the console. Not recommended unless bug testing specifically. +Page=General +Group=Debugging + +[Setting] +Name=UseDebugSettings +Title=Use debug settings +Type=TickBox +Default=0 +Tooltip=If enabled, allows a secondary mod to force certain parts of the randomiser. +Page=General +Group=Debugging + [Setting] Name=RandomCouch Title=Random couch character @@ -3945,64 +4029,26 @@ Tooltip=Attempts to randomise the UFO locations in levels. Page=Chaos Randomisations Testing=1 -[Setting] -Name=SkipLocks -Title=Remove car/costume requirements -Type=TickBox -Default=0 -Tooltip=Remove specific car/costume requirements from certain missions -Page=Misc - -[Setting] -Name=SkipFMVs -Title=Skip cutscenes (except intro cutscene) -Type=TickBox -Default=0 -Tooltip=Remove all in-game cutscenes, including the ones at the end of levels. The intro cutscene can be skipped by enabling "No Introduction Movies" -Page=Misc - -[Setting] -Name=BoostHP -Title=Increase HP for weak cars -Type=TickBox -Default=0 -Tooltip=Slightly increases HP for weak vehicles like the rocket car -Page=Misc - -[Setting] -Name=DebugLevel -Title=Debug level -Type=Number -Integer=1 -Min=0 -Max=5 -Default=0 -Tooltip=Sets the debug level for console printing - 0 will print only the basics whilst 5 will print everything -Page=Misc - -[Setting] -Name=SpeedrunMode -Title=Speedrun Mode -Type=TickBox -Default=0 -Tooltip=Enables the speedrun settings viable for the leaderboards -Page=Misc +[SettingCondition] +Type=Setting +Setting=RandomItemsIncludeChars +Value=1 +ConditionSetting=RandomItems +Operator=EqualTo -[Setting] -Name=VerboseDebug -Title=Verbose debug -Type=TickBox -Default=0 -Tooltip=If enabled, outputs all modified files to the console. Not recommended unless bug testing specifically. -Page=Misc +[SettingCondition] +Type=Setting +Setting=RandomItemsIncludeCars +Value=1 +ConditionSetting=RandomItems +Operator=EqualTo -[Setting] -Name=UseDebugSettings -Title=Use debug settings -Type=TickBox -Default=0 -Tooltip=If enabled, allows a secondary mod to force certain parts of the randomiser. -Page=Misc +[SettingCondition] +Type=Setting +Setting=RemoveOutOfCar +Value=1 +ConditionSetting=RandomPlayerVehicles +Operator=EqualTo [SettingCondition] Type=Setting @@ -4564,6 +4610,13 @@ Value=1 ConditionSetting=SuperRandomDialogue Operator=EqualTo +[SettingCondition] +Type=Setting +Setting=Seed +Value=1 +ConditionSetting=IsSeeded +Operator=EqualTo + ;[SettingWarning] ;Setting=RandomCarSounds ;Operator=EqualTo diff --git a/Randomiser/Resources/CustomCars.lua b/Randomiser/Resources/CustomCars.lua index f329cc0..1d8915a 100644 --- a/Randomiser/Resources/CustomCars.lua +++ b/Randomiser/Resources/CustomCars.lua @@ -70,7 +70,7 @@ if IsModEnabled("RandomiserCars") then end end else - DebugPrint("No carsound.spt found for Custom Car " .. customCarName .. ".") + DebugPrint("No carsound.spt found for Custom Car " .. customCarName .. ".", 3) end end end diff --git a/Randomiser/Resources/CustomText.lua b/Randomiser/Resources/CustomText.lua index 5b2c484..cf70ad1 100644 --- a/Randomiser/Resources/CustomText.lua +++ b/Randomiser/Resources/CustomText.lua @@ -82,6 +82,12 @@ for k, v in pairs(ChaosSettings) do end local Values = os.date("[%Y-%m-%d]") .. "\n" .. ModName .. " v" .. ModVersion .. (Settings.SpeedrunMode and " (speedrun)" or "").. (Settings.UseDebugSettings and " (debug)" or "") .. "\n" .. string.format("Settings: Gameplay: %X, Graphics: %X, Chaos: %X", GameplayN, GraphicalN, ChaosN) +if Settings.IsSeeded then + Values = Values .. string.format("\nSeed: %s, Check: %s", Settings.Seed, Seed.CheckWord()) + if ChaosN > 0 then + Alert("Chaos randomisations are not seeded and should be disabled for consistent races") + end +end local Chunk = P3D.P3DChunk:new{Raw = ReadFile(Path)} local BibleIdx = Chunk:GetChunkIndex(P3D.Identifiers.Frontend_Text_Bible) diff --git a/Randomiser/Resources/GlobalFunctions.lua b/Randomiser/Resources/GlobalFunctions.lua index e873f05..43685c2 100644 --- a/Randomiser/Resources/GlobalFunctions.lua +++ b/Randomiser/Resources/GlobalFunctions.lua @@ -77,6 +77,17 @@ function CloneKVTable(tbl) return clone end +function MergeTable(t1, t2) + for k, v in pairs(t2) do + if (type(v) == "table") and (type(t1[k] or false) == "table") then + merge(t1[k], t2[k]) + else + t1[k] = v + end + end + return t1 +end + function CountTable(tbl) local count = 0 for _ in pairs(tbl) do @@ -123,6 +134,8 @@ function GetFiles(tbl, dir, extensions, count, topLevelOnly) end return true end) + -- Deterministic GetFiles for seeding (case insensitive in case the cases are messed up somehow) + table.sort(tbl, function (a, b) return a:upper() < b:upper() end) end function GetDirs(tbl, dir) @@ -135,14 +148,22 @@ function GetDirs(tbl, dir) end -local bs = { [0] = +local std_bs = { [0] = 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', } -function base64(s) +local std_bsi = {} +for i=0,#std_bs do + std_bsi[string.byte(std_bs[i])] = i +end + +function base64(s, bs) + if bs == nil then + bs = std_bs + end local byte, rep = string.byte, string.rep local pad = 2 - ((#s-1) % 3) s = (s..rep('\0', pad)):gsub("...", function(cs) @@ -152,6 +173,35 @@ function base64(s) return s:sub(1, #s-pad) .. rep('=', pad) end +function base64dec(s, bs, bsi) + if bs == nil then + bs = std_bs + bsi = std_bsi + end + if bsi == nil then + bsi = {} + for i=0,#bs do + bsi[string.byte(bs[i])] = i + end + end + s = s:gsub("[^A" .. table.concat(bs) .. "=]", "") + local p = '' + if s:sub(#s) == '=' then + if s:sub(#s - 1) == '=' then + p = 'AA' + else + p = 'A' + end + s = s:sub(1, #s - #p) .. p + end + s = s:gsub("....", function(cs) + local a, b, c, d = string.byte(cs, 1, 4) + local n = (bsi[a] << 18) + (bsi[b] << 12) + (bsi[c] << 6) + bsi[d] + return string.char((n >> 16) & 255, (n >> 8) & 255, n & 255) + end) + return s:sub(1, #s - #p) +end + function DebugPrint(msg, level) if level == nil then level = 0 diff --git a/Randomiser/Resources/HandleCharModel.lua b/Randomiser/Resources/HandleCharModel.lua index 2bc82ed..84f6538 100644 --- a/Randomiser/Resources/HandleCharModel.lua +++ b/Randomiser/Resources/HandleCharModel.lua @@ -138,6 +138,8 @@ if Exists("/GameData/" .. Path, true, false) then end end end -elseif Settings.RandomPedestrians and Settings.CustomChars and (ExistsInTbl(LevelPedestrians, FileName) or ExistsInTbl(MissionDrivers, FileName)) and CustomChars[FileName] then - Output(ReadFile(CustomChars[FileName])) +--elseif Settings.RandomPedestrians and Settings.CustomChars and (ExistsInTbl(LevelPedestrians, FileName) or ExistsInTbl(MissionDrivers, FileName)) and CustomChars[FileName] then + --Output(ReadFile(CustomChars[FileName])) +elseif Settings.CustomChars and CustomChars[FileName] then + Redirect(CustomChars[FileName]) end diff --git a/Randomiser/Resources/HandleIngame.lua b/Randomiser/Resources/HandleIngame.lua new file mode 100644 index 0000000..732a3e3 --- /dev/null +++ b/Randomiser/Resources/HandleIngame.lua @@ -0,0 +1,34 @@ +local Path = "/GameData/" .. GetPath() + +if Cache.Ingame then + Output(Cache.Ingame) + return +end + +local Chunk = P3D.P3DChunk:new{Raw = ReadFile(Path)} +local ProjectIDX = Chunk:GetChunkIndex(P3D.Identifiers.Frontend_Project) +local ProjectChunk = P3D.FrontendProjectP3DChunk:new{Raw = Chunk:GetChunkAtIndex(ProjectIDX)} +local PageIDX = nil +local PageChunk = nil +for idx in ProjectChunk:GetChunkIndexes(P3D.Identifiers.Frontend_Page) do + PageChunk = P3D.FrontendPageP3DChunk:new{Raw = ProjectChunk:GetChunkAtIndex(idx)} + if P3D.CleanP3DString(PageChunk.Name) == "Pause.pag" then + PageIDX = idx + break + end +end +if PageIDX then + local TextStyleChunk = P3D.FrontendTextStyleResourceP3DChunk:create(P3D.MakeP3DString("font1_14"),1,P3D.MakeP3DString("fonts\\font1_14.p3d"),P3D.MakeP3DString("Tt2001m__14")) + PageChunk:AddChunk(TextStyleChunk:Output(), 1) + local LayerIDX = PageChunk:GetChunkIndex(P3D.Identifiers.Frontend_Layer) + local LayerChunk = P3D.FrontendLayerP3DChunk:new{Raw = PageChunk:GetChunkAtIndex(LayerIDX)} + local MultiTextChunk = P3D.FrontendMultiTextP3DChunk:create(P3D.MakeP3DString("RandoSettings"), 17, 220, 75, 200, 18, P3D.FrontendMultiTextP3DChunk.Justifications.Centre, P3D.FrontendMultiTextP3DChunk.Justifications.Top, {A=255,R=255,G=255,B=255}, 0, 0, P3D.MakeP3DString("font1_14"), 1, {A=192,R=0,G=0,B=0}, 2, -2, 0) + local TextChunk = P3D.FrontendStringTextBibleP3DChunk:create("srr2", P3D.MakeP3DString("RandoSettings")) + MultiTextChunk:AddChunk(TextChunk:Output()) + LayerChunk:AddChunk(MultiTextChunk:Output()) + PageChunk:SetChunkAtIndex(LayerIDX, LayerChunk:Output()) + ProjectChunk:SetChunkAtIndex(PageIDX, PageChunk:Output()) + Chunk:SetChunkAtIndex(ProjectIDX, ProjectChunk:Output()) + Cache.Ingame = Chunk:Output() + Output(Cache.Ingame) +end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomCharacter.lua b/Randomiser/Resources/MissionModules/RandomCharacter.lua index 6f5fd45..bfd1979 100644 --- a/Randomiser/Resources/MissionModules/RandomCharacter.lua +++ b/Randomiser/Resources/MissionModules/RandomCharacter.lua @@ -11,6 +11,6 @@ if Settings.RandomCharacter then function Level.RandomCharacter(LoadFile, InitFile, Level, Path) OrigChar = InitFile:match("AddCharacter%s*%(%s*\"([^\n]-)\"") - return LoadFile, InitFile + return LoadFile, InitFile, { "OrigChar" } end end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomChase.lua b/Randomiser/Resources/MissionModules/RandomChase.lua index 088bc86..0eadcc7 100644 --- a/Randomiser/Resources/MissionModules/RandomChase.lua +++ b/Randomiser/Resources/MissionModules/RandomChase.lua @@ -14,7 +14,7 @@ if Settings.RandomChase then else Mission = tbl.Mission[sort] end - + function Level.RandomChase(LoadFile, InitFile, Level, Path) RandomChase = GetRandomFromTbl(RandomCarPoolChase, false) if Settings.UseDebugSettings and Exists("/GameData/RandomiserSettings/RandomChaseCar.txt", true, false) then @@ -32,11 +32,12 @@ if Settings.RandomChase then InitFile = InitFile:gsub("CreateChaseManager%s*%(%s*\"[^\n]-\"", "CreateChaseManager(\"" .. RandomChase .."\"", 1) end if Settings.RandomChaseAmount then - local chaseAmount = math.random(1, 5) + local chaseAmount + chaseAmount = math.random(1, 5) InitFile = InitFile:gsub("SetNumChaseCars%s*%(%s*\"[^\n]-\"", "SetNumChaseCars(\"" .. chaseAmount .."\"", 1) DebugPrint("Random chase amount -> " .. chaseAmount) end - return LoadFile, InitFile + return LoadFile, InitFile, { "RandomChase" } end function Mission.RandomChase(LoadFile, InitFile, Level, Mission, Path) diff --git a/Randomiser/Resources/MissionModules/RandomDirectives.lua b/Randomiser/Resources/MissionModules/RandomDirectives.lua index f1b2dbf..89d3dfa 100644 --- a/Randomiser/Resources/MissionModules/RandomDirectives.lua +++ b/Randomiser/Resources/MissionModules/RandomDirectives.lua @@ -254,7 +254,7 @@ if Settings.RandomDirectives then for orig,rand in pairs(iconReplace) do InitFile = InitFile:gsub("SetHUDIcon%s*%(%s*\"" .. orig .. "\"%s*%)", "SetHUDIcon(\"" .. rand .. "\")") end - return LoadFile, InitFile + return LoadFile, InitFile, { "iconReplace" } end Mission.RandomDirectives = SundayDrive.RandomDirectives end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomMissionCharacters.lua b/Randomiser/Resources/MissionModules/RandomMissionCharacters.lua index a24ddd4..069b690 100644 --- a/Randomiser/Resources/MissionModules/RandomMissionCharacters.lua +++ b/Randomiser/Resources/MissionModules/RandomMissionCharacters.lua @@ -26,7 +26,7 @@ if Settings.RandomMissionCharacters then for npc in InitFile:gmatch("AddNPCCharacterBonusMission%s*%(%s*\"([^\n]-)\"") do table.insert(BonusCharacters, npc) end - return LoadFile, InitFile + return LoadFile, InitFile, { "BonusCharacters" } end function SundayDrive.RandomMissionCharacters(LoadFile, InitFile, Level, Mission, Path) @@ -37,7 +37,7 @@ if Settings.RandomMissionCharacters then found = found .. npc .. ", " end DebugPrint(found) - return LoadFile, InitFile + return LoadFile, InitFile, { "MissionCharacters" } end Mission.RandomMissionCharacters = SundayDrive.RandomMissionCharacters end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomMissionVehicles.lua b/Randomiser/Resources/MissionModules/RandomMissionVehicles.lua index 66797f2..da17e0d 100644 --- a/Randomiser/Resources/MissionModules/RandomMissionVehicles.lua +++ b/Randomiser/Resources/MissionModules/RandomMissionVehicles.lua @@ -23,15 +23,15 @@ if Settings.RandomMissionVehicles then function Level.RandomMissionVehicles(LoadFile, InitFile, Level, Path) LastLevelMV = nil - return LoadFile, InitFile + return LoadFile, InitFile, { "LastLevelMV" } end function SundayDrive.RandomMissionVehicles(LoadFile, InitFile, Level, Mission, Path) LastLevelMV = nil - return LoadFile, InitFile + return LoadFile, InitFile, { "LastLevelMV" } end - - function Mission.RandomMissionVehicldes(LoadFile, InitFile, Level, Mission, Path) + + local function Mission_RandomMissionVehicles(LoadFile, InitFile, Level, Mission, Path) DebugPrint("Checking for sub level cars in " .. Level .. "|" .. Mission) local randomise = not Settings.SaveChoiceMV or LastLevelMV == nil or LastLevelMV ~= Path LastLevelMV = Path @@ -105,6 +105,8 @@ if Settings.RandomMissionVehicles then end return "AddStageVehicle(\"" .. car .. "\",\"" .. position .. "\",\"" .. action .. "\",\"" .. config .. "\",\"" .. orig .. "\");" end) - return LoadFile, InitFile + return LoadFile, InitFile, { "LastLevelMV", "MissionDrivers", "MissionVehicles" } end + + Mission.RandomMissionVehicles = Mission_RandomMissionVehicles end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomMissions.lua b/Randomiser/Resources/MissionModules/RandomMissions.lua index 95a67fe..809d04e 100644 --- a/Randomiser/Resources/MissionModules/RandomMissions.lua +++ b/Randomiser/Resources/MissionModules/RandomMissions.lua @@ -9,7 +9,7 @@ if Settings.RandomMissions then Level = tbl.Level[sort] end - function Level.RandomMissions(LoadFile, InitFile, Level, Path) + local function Level_RandomMissions(LoadFile, InitFile, Level, Path) local missions = {} for mission in LoadFile:gmatch("AddMission%s*%(%s*\"m(%d)\"") do if tonumber(mission) < 8 then @@ -44,4 +44,6 @@ if Settings.RandomMissions then end) return LoadFile, InitFile end + + Level.RandomMissions = Level_RandomMissions end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomPedestrians.lua b/Randomiser/Resources/MissionModules/RandomPedestrians.lua index 478a68c..592bd50 100644 --- a/Randomiser/Resources/MissionModules/RandomPedestrians.lua +++ b/Randomiser/Resources/MissionModules/RandomPedestrians.lua @@ -9,7 +9,7 @@ if Settings.RandomPedestrians then Level = tbl.Level[sort] end - function Level.RandomPedestrians(LoadFile, InitFile, Level, Path) + local function Level_RandomPedestrians(LoadFile, InitFile, Level, Path) local TmpPedPool = {table.unpack(RandomPedPool)} local groups = {} for group in InitFile:gmatch("CreatePedGroup%s*%(%s*(%d)%s*%);") do @@ -59,6 +59,8 @@ if Settings.RandomPedestrians then LevelCharacters[#LevelCharacters + 1] = npc end DebugPrint("Random pedestrians for level -> " .. table.concat(LevelPedestrians, ", ")) - return LoadFile, InitFile + return LoadFile, InitFile, { "LevelPedestrians" } end + + Level.RandomPedestrians = Level_RandomPedestrians end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomPlayerVehicles.lua b/Randomiser/Resources/MissionModules/RandomPlayerVehicles.lua index 66ae9f3..ea5ebee 100644 --- a/Randomiser/Resources/MissionModules/RandomPlayerVehicles.lua +++ b/Randomiser/Resources/MissionModules/RandomPlayerVehicles.lua @@ -30,16 +30,19 @@ if Settings.RandomPlayerVehicles then InitFile = InitFile:gsub("InitLevelPlayerVehicle%s*%(%s*\"[^\n]-\"%s*,%s*\"([^\n]-)\"%s*,%s*\"DEFAULT\"%s*%)", "InitLevelPlayerVehicle(\"" .. RandomCarName .. "\",\"%1\",\"DEFAULT\")", 1) DebugPrint("Randomising car for level -> " .. RandomCarName) - return LoadFile, InitFile + return LoadFile, InitFile, { "LastLevel", "RandomCar", "RandomCarName" } end - function Mission.RandomPlayerVehicles(LoadFile, InitFile, Level, Mission, Path) + function Mission.RandomPlayerVehicles(LoadFile, InitFile, Level, Mission, Path, Type) if SettingSaveChoice then if LastLevel ~= Path then - RandomCar = math.random(#RandomCarPoolPlayer) + RandomCar = nil end LastLevel = Path else + RandomCar = nil + end + if RandomCar == nil then RandomCar = math.random(#RandomCarPoolPlayer) end RandomCarName = RandomCarPoolPlayer[RandomCar] @@ -115,6 +118,6 @@ if Settings.RandomPlayerVehicles then end) end - return LoadFile, InitFile + return LoadFile, InitFile, { "LastLevel", "RandomCar", "RandomCarName" } end end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomStaticCars.lua b/Randomiser/Resources/MissionModules/RandomStaticCars.lua index b62d29f..aab48b6 100644 --- a/Randomiser/Resources/MissionModules/RandomStaticCars.lua +++ b/Randomiser/Resources/MissionModules/RandomStaticCars.lua @@ -13,6 +13,6 @@ if Settings.SaveChoiceRSC then function Level.RandomStaticCar(LoadFile, InitFile, Level, Mission, Path) RandomStaticCarSave = {} - return LoadFile, InitFile + return LoadFile, InitFile, { "RandomStaticCar" } end end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomTraffic.lua b/Randomiser/Resources/MissionModules/RandomTraffic.lua index b9ad2f4..3fa52f4 100644 --- a/Randomiser/Resources/MissionModules/RandomTraffic.lua +++ b/Randomiser/Resources/MissionModules/RandomTraffic.lua @@ -11,8 +11,8 @@ if Settings.RandomTraffic then function Level.RandomTraffic(LoadFile, InitFile, Level, Path) TrafficCars = {} - local TmpCarPool = {table.unpack(RandomCarPoolTraffic)} local Cars = "" + local TmpCarPool = {table.unpack(RandomCarPoolTraffic)} for i = 1, math.min(5, #TmpCarPool) do local carName = GetRandomFromTbl(TmpCarPool, true) table.insert(TrafficCars, carName) @@ -48,12 +48,14 @@ if Settings.RandomTraffic then end end local parked = "" - if math.random(3) == 1 then + local parked_check + parked_check = math.random(3) + if parked_check == 1 then parked = ",1" end InitFile = InitFile .. "\r\nAddTrafficModel( \"" .. carName .. "\"," .. amount .. parked .. " );" end InitFile = InitFile .. "\r\nCloseTrafficGroup( );" - return LoadFile, InitFile + return LoadFile, InitFile, { "TrafficCars" } end end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomUFOs.lua b/Randomiser/Resources/MissionModules/RandomUFOs.lua index 51a3652..291fff2 100644 --- a/Randomiser/Resources/MissionModules/RandomUFOs.lua +++ b/Randomiser/Resources/MissionModules/RandomUFOs.lua @@ -27,6 +27,6 @@ AddFlyingActorByLocator("spaceship","Planet Express Ship","l]] AddBehaviour( "Planet Express Ship", "UFO_BEAM_ALWAYS_ON", "UfoBeam" );]] UFO = "l" .. Level .. "_spaceship" end - return LoadFile, InitFile + return LoadFile, InitFile, { "UFO" } end end \ No newline at end of file diff --git a/Randomiser/Resources/MissionModules/RandomWaypoints.lua b/Randomiser/Resources/MissionModules/RandomWaypoints.lua index 24d9137..3490cf4 100644 --- a/Randomiser/Resources/MissionModules/RandomWaypoints.lua +++ b/Randomiser/Resources/MissionModules/RandomWaypoints.lua @@ -47,11 +47,11 @@ if Settings.RandomWaypoints then DebugPrint("Found " .. GetWaypoints(sdInit) .. " waypoints in L" .. Level .. "SD" .. i, 2) end end - return LoadFile, InitFile + return LoadFile, InitFile, { "Waypoints" } end - function Mission.RandomWaypoints(LoadFile, InitFile, Level, Mission, Path, IsRace) - if not IsRace then + function Mission.RandomWaypoints(LoadFile, InitFile, Level, Mission, Path, Type) + if Type ~= MissionType.Race and Type ~= MissionType.GamblingRace then Waypoints = {} local WaypointN = GetWaypoints(InitFile) if WaypointN > 0 then @@ -67,6 +67,6 @@ if Settings.RandomWaypoints then DebugPrint("Found " .. WaypointN .. " waypoints in L" .. Level .. "M" .. Mission .. ".") end end - return LoadFile, InitFile + return LoadFile, InitFile, { "Waypoints" } end end \ No newline at end of file diff --git a/Randomiser/Resources/MissionScripts/HandleLevelLoad.lua b/Randomiser/Resources/MissionScripts/HandleLevelLoad.lua index cc2fae1..153faef 100644 --- a/Randomiser/Resources/MissionScripts/HandleLevelLoad.lua +++ b/Randomiser/Resources/MissionScripts/HandleLevelLoad.lua @@ -1,5 +1,11 @@ local Path = "/GameData/" .. GetPath(); loading = true + +if Settings.IsSeeded then + Seed.HandleModulesLevel(Path) + return +end + if MissionModules.Level then local level = tonumber(Path:match("level0(%d)")) DebugPrint("NEW LEVEL LOAD: Level " .. level) @@ -19,4 +25,4 @@ if MissionModules.Level then DebugPrint("Level Init File:\r\n" .. InitFile) end Output(LoadFile) -end \ No newline at end of file +end diff --git a/Randomiser/Resources/MissionScripts/HandleMissionLoad.lua b/Randomiser/Resources/MissionScripts/HandleMissionLoad.lua index 7d0b79f..168ec8b 100644 --- a/Randomiser/Resources/MissionScripts/HandleMissionLoad.lua +++ b/Randomiser/Resources/MissionScripts/HandleMissionLoad.lua @@ -1,18 +1,40 @@ local Path = "/GameData/" .. GetPath(); loading = true + +if Settings.IsSeeded then + Seed.HandleModulesMission(Path) + return +end + + if MissionModules.Mission then local level = tonumber(Path:match("level0(%d)")) - local prefix, mission = Path:match("([rm])(%d)l") + local prefix, mission = Path:match("([bsg]?[rm])(%d)l") mission = tonumber(mission) - local isRace = prefix == "r" - DebugPrint("NEW MISSION/RACE LOAD: Level " .. level .. ", " .. (isRace and "Race " or "Mission ") .. mission) + local misstype, missname + if prefix == "m" then + misstype = MissionType.Normal + missname = "Mission" + elseif prefix == "sr" then + misstype = MissionType.Race + missname = "Race" + elseif prefix == "bm" then + misstype = MissionType.BonusMission + missname = "Bonus Mission" + elseif prefix == "gr" then + misstype = MissionType.GamblingRace + missname = "Gambling Race" + else + error("unknown mission script type") + end + DebugPrint("NEW MISSION/RACE LOAD: Level " .. level .. ", " .. missname .. " " .. mission) local LoadFile = ReadFile(Path):gsub("//.-([\r\n])", "%1"); local InitFile = ReadFile(Path:gsub("l%.mfk", "i.mfk")):gsub("//.-([\r\n])", "%1"); for i = MissionMin,MissionMax do if MissionModules.Mission[i] then for k,v in pairs(MissionModules.Mission[i]) do DebugPrint("Running module: " .. k, 2) - LoadFile, InitFile = v(LoadFile, InitFile, level, mission, Path, isRace) + LoadFile, InitFile = v(LoadFile, InitFile, level, mission, Path, misstype) end end end diff --git a/Randomiser/Resources/MissionScripts/HandleSDLoad.lua b/Randomiser/Resources/MissionScripts/HandleSDLoad.lua index e3bb9e5..97d24e3 100644 --- a/Randomiser/Resources/MissionScripts/HandleSDLoad.lua +++ b/Randomiser/Resources/MissionScripts/HandleSDLoad.lua @@ -1,5 +1,11 @@ local Path = "/GameData/" .. GetPath(); loading = true + +if Settings.IsSeeded then + Seed.HandleModulesSDMission(Path) + return +end + if MissionModules.SundayDrive then local level = tonumber(Path:match("level0(%d)")) local mission = tonumber(Path:match("m(%d)sdl")) diff --git a/Randomiser/Resources/MissionScripts/LoadModules.lua b/Randomiser/Resources/MissionScripts/LoadModules.lua index 1627129..f500729 100644 --- a/Randomiser/Resources/MissionScripts/LoadModules.lua +++ b/Randomiser/Resources/MissionScripts/LoadModules.lua @@ -3,11 +3,19 @@ MissionModules.Level = {} MissionModules.Mission = {} MissionModules.SundayDrive = {} +MissionType = +{ + Normal = 1, + Race = 2, + BonusMission = 3, + GamblingRace = 4 +} + local ModuleFiles = {} GetFiles(ModuleFiles, Paths.MissionModules, {".lua"}, 1) for i=1, #ModuleFiles do DebugPrint("Loading module: " .. ModuleFiles[i], 2) - loadfile(ModuleFiles[i])(MissionModules) + assert(loadfile(ModuleFiles[i]))(MissionModules) end LevelMin = 0 @@ -54,4 +62,10 @@ for k,_ in pairs(MissionModules.SundayDrive) do else SundayMax = math.max(SundayMax, i) end -end \ No newline at end of file +end + +if Settings.IsSeeded then + DebugPrint("Generating seeded mission scripts") + Seed.CacheModules() +end + diff --git a/Randomiser/Resources/checkwords.txt b/Randomiser/Resources/checkwords.txt new file mode 100644 index 0000000..6ad6d8c --- /dev/null +++ b/Randomiser/Resources/checkwords.txt @@ -0,0 +1,101 @@ +ATV +AMBULANCE +ARMORED TRUCK +BABYVAN +BARRACUDA +BEARCAT +BLACK FERRINI +BONESTORM +BOOK BURNING +BURNS LIMO +CANYONERO +CAR BUILT FOR HOMER +CELL PHONE CAR +CLETUS PICKUP +COFFIN CAR +COLA TRUCK +CUBE VAN +CURATOR +DONUT TRUCK +DUFF TRUCK +EL CAMINO +ELECTAURUS +FBI VAN +FAMILY SEDAN +FERRINI +FIRE TRUCK +FISH TRUCK +GARBAGE TRUCK +GLASS TRUCK +GLOBEX +GREMLIN +HEARSE +HONOR ROLLER +HOVER BIKE +HOVER CAR +HUSK +ICE CREAM TRUCK +KNIGHT BOAT +KRUSTYS LIMO +LIL BANDIT +LIMO +LONGHORN +MALIBU STACY CAR +MILK TRUCK +MINIVAN +MONORAIL +MONSTER TRUCK +MR PLOW TRUCK +NERD CAR +OPEN WHEEL RACE CAR +PLANET HYPE CAR +PLOW KING +POLICE CAR +RED BRICK CAR +ROCKET CAR +SCHOOL BUS +SEDAN +SKINNERS SEDAN +TAXI +TRACTOR +WWII JEEP +ZOMBIE CAR +AGNES +APU +BART +BEEMAN +CARL +CLETUS +COMIC BOOK GUY +DOLPH +DR HIBBERT +DR NICK +EDDIE +GIL +GRANDPA +HOMER +JASPER +JIMBO +KEARNEY +KRUSTY +LENNY +LISA +LOU +LOUIE +MARGE +MILHOUSE +MOE +MOLEMAN +MR BURNS +NELSON +OTTO +PATTY +PROFESSOR FRINK +RALPH +SEA CAPTAIN +SELMA +SKINNER +SMITHERS +SNAKE +WIGGUM +WILLIE \ No newline at end of file diff --git a/Randomiser/Resources/lib/Seed.lua b/Randomiser/Resources/lib/Seed.lua new file mode 100644 index 0000000..3fd6df5 --- /dev/null +++ b/Randomiser/Resources/lib/Seed.lua @@ -0,0 +1,381 @@ +Seed = {} +Seed.Spoiler = {} + +Seed.MAX_LEVELS = 7 +Seed.MAX_MISSIONS = 15 + +local MAX_ATTEMPTS_MISSIONS = 5 +local MAX_ATTEMPTS_LEVELS = 1 + +Seed.CachedLevel = {} +Seed.CachedMission = {} +Seed.CachedSDMission = {} + +-- Special Base64 Array to avoid "similar" letters +Seed._bs = { [0] = + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','%','j','k','&','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','$','2','3','4','5','6','7','8','9','+','/', +} + +-- Inverse lookup for base64 +Seed._bsi = {} +for i=0,#Seed._bs do + Seed._bsi[string.byte(Seed._bs[i])] = i +end + +function Seed.Base64(s) + return base64(s, Seed._bs):sub(1, -2) +end + +function Seed.Base64dec(s) + return base64dec(s .. "=", Seed._bs, Seed._bsi) +end + +function Seed.CheckWord() + if Seed._CHECKWORD ~= nil then + return Seed._CHECKWORD + end + + local wordstxt = ReadFile(Paths.Resources .. "checkwords.txt") + local words = {} + for s in wordstxt:gmatch("[^\r\n]+") do + table.insert(words, s) + end + + Seed._CHECKWORD = GetRandomFromTbl(words) + DebugPrint("Seed checkword is: " .. Seed._CHECKWORD) + return Seed._CHECKWORD +end + +-- Always iterate modules in Seeded mode with spairs which runs in a deterministic order! +-- Otherwise the seeded is still random! +local function spairs(t, f) + local a = {} + for n in pairs(t) do table.insert(a, n) end + table.sort(a, f) + local i = 0 + local iter = function() + i = i + 1 + if a[i] == nil then return nil + else return a[i], t[a[i]] + end + end + return iter +end + +function Seed.InternalCacheModulesLevel(i) + Seed.AddSpoiler("Caching level: %s", i) + local Path = string.format("/GameData/scripts/missions/level%02d/level.mfk", i) + -- Generate structure for seeded level files + if Seed.CachedLevel[Path] == nil then + Seed.CachedLevel[Path] = {} + Seed.CachedLevel[Path].Attempt = 1 + Seed.CachedLevel[Path].LoadFile = {} + Seed.CachedLevel[Path].InitFile = {} + Seed.CachedLevel[Path].Globals = {} + for j=1,MAX_ATTEMPTS_LEVELS do + Seed.CachedLevel[Path].LoadFile[j] = ReadFile(Path):gsub("//.-([\r\n])", "%1"); + Seed.CachedLevel[Path].InitFile[j] = ReadFile(Path:gsub("level%.mfk", "leveli.mfk")):gsub("//.-([\r\n])", "%1"); + Seed.CachedLevel[Path].Globals[j] = {} + end + end + + local old_DebugPrint = DebugPrint + DebugPrint = function(msg, level) + Seed.AddSpoiler(msg) + end + for j=1,MAX_ATTEMPTS_LEVELS do + Seed.AddSpoiler("Seeding attempt #%d", j) + for l = LevelMin,LevelMax do + if MissionModules.Level[l] then + for k, v in spairs(MissionModules.Level[l]) do + Seed.AddSpoiler("Running module: " .. k) + local globals, g2 + Seed.CachedLevel[Path].LoadFile[j], Seed.CachedLevel[Path].InitFile[j], globals = v(Seed.CachedLevel[Path].LoadFile[j], Seed.CachedLevel[Path].InitFile[j], i, Path) + if globals ~= nil then + g2 = {} + for kk, vv in pairs(globals) do + g2[vv] = _G[vv] + end + Seed.CachedLevel[Path].Globals[j] = MergeTable(Seed.CachedLevel[Path].Globals[j], g2) + end + end + end + end + end + DebugPrint = old_DebugPrint +end + +function Seed.InternalCacheModuleMission(i, Path, j, prefix, mission) + Seed.AddSpoiler("Caching mission: %s", Path) + mission = tonumber(mission) + local misstype + if prefix == "m" then + misstype = MissionType.Normal + elseif prefix == "sr" then + misstype = MissionType.Race + elseif prefix == "bm" then + misstype = MissionType.BonusMission + elseif prefix == "gr" then + misstype = MissionType.GamblingRace + else + error("unknown mission script type") + end + + -- Generate structure for seeded mission files + if Seed.CachedMission[Path] == nil then + Seed.CachedMission[Path] = {} + Seed.CachedMission[Path].Attempt = 1 + Seed.CachedMission[Path].LoadFile = {} + Seed.CachedMission[Path].InitFile = {} + Seed.CachedMission[Path].Globals = {} + for m=1,MAX_ATTEMPTS_MISSIONS do + Seed.CachedMission[Path].LoadFile[m] = ReadFile(Path):gsub("//.-([\r\n])", "%1"); + Seed.CachedMission[Path].InitFile[m] = ReadFile(Path:gsub("l%.mfk", "i.mfk")):gsub("//.-([\r\n])", "%1"); + Seed.CachedMission[Path].Globals[m] = {} + end + end + + local old_DebugPrint = DebugPrint + DebugPrint = function(msg, level) + Seed.AddSpoiler(msg) + end + for m=1,MAX_ATTEMPTS_MISSIONS do + Seed.AddSpoiler("Seeding attempt #%d", m) + for l = MissionMin,MissionMax do + if MissionModules.Mission[l] then + for k, v in spairs(MissionModules.Mission[l]) do + Seed.AddSpoiler("Running module: " .. k) + local globals, g2 + Seed.CachedMission[Path].LoadFile[m], Seed.CachedMission[Path].InitFile[m], globals = v(Seed.CachedMission[Path].LoadFile[m], Seed.CachedMission[Path].InitFile[m], i, mission, Path, misstype) + if globals ~= nil then + g2 = {} + for kk, vv in pairs(globals) do + g2[vv] = _G[vv] + end + Seed.CachedMission[Path].Globals[m] = MergeTable(Seed.CachedMission[Path].Globals[m], g2) + end + end + end + end + end + DebugPrint = old_DebugPrint +end + +function Seed.InternalCacheModuleSDMission(i, Path, j, prefix, mission) + Seed.AddSpoiler("Caching SD mission: %s", Path) + mission = tonumber(mission) + + -- Generate structure for seeded sunday drive files + if Seed.CachedSDMission[Path] == nil then + Seed.CachedSDMission[Path] = {} + Seed.CachedSDMission[Path].Attempt = 1 + Seed.CachedSDMission[Path].LoadFile = {} + Seed.CachedSDMission[Path].InitFile = {} + Seed.CachedSDMission[Path].Globals = {} + for m=1,MAX_ATTEMPTS_MISSIONS do + Seed.CachedSDMission[Path].LoadFile[m] = ReadFile(Path):gsub("//.-([\r\n])", "%1"); + Seed.CachedSDMission[Path].InitFile[m] = ReadFile(Path:gsub("sdl%.mfk", "sdi.mfk")):gsub("//.-([\r\n])", "%1"); + Seed.CachedSDMission[Path].Globals[m] = {} + end + end + + local old_DebugPrint = DebugPrint + DebugPrint = function(msg, level) + Seed.AddSpoiler(msg) + end + for m=1,MAX_ATTEMPTS_MISSIONS do + Seed.AddSpoiler("Seeding attempt #%d", m) + for l = SundayMin,SundayMax do + if MissionModules.SundayDrive[l] then + for k, v in spairs(MissionModules.SundayDrive[l]) do + Seed.AddSpoiler("Running module: " .. k) + local globals, g2 + Seed.CachedSDMission[Path].LoadFile[m], Seed.CachedSDMission[Path].InitFile[m], globals = v(Seed.CachedSDMission[Path].LoadFile[m], Seed.CachedSDMission[Path].InitFile[m], i, mission, Path) + if globals ~= nil then + g2 = {} + for kk, vv in pairs(globals) do + g2[vv] = _G[vv] + end + Seed.CachedSDMission[Path].Globals[m] = MergeTable(Seed.CachedSDMission[Path].Globals[m], g2) + end + end + end + end + end + DebugPrint = old_DebugPrint +end + +function Seed.CacheModules() + for i=1,Seed.MAX_LEVELS do + Seed.InternalCacheModulesLevel(i) + local path = string.format("/GameData/scripts/missions/level%02d/", i) + local files = {} + GetFiles(files, path, {".mfk"}) + for j=1,#files do + local Path = files[j] + local prefix, mission = Path:match("([bsg]?[rm])(%d)l") + if prefix ~= nil and mission ~= nil then + Seed.InternalCacheModuleMission(i, Path, j, prefix, mission) + end + mission = Path:match("m(%d)sdl") + if mission ~= nil then + Seed.InternalCacheModuleSDMission(i, Path, j, prefix, mission) + end + end + end + + Seed.CheckWord() +end + +function Seed.HandleModulesLevel(Path) + if Seed.CachedLevel[Path] == nil then + DebugPrint("Request for Path " .. Path .. " was not seeded, falling back to normal generation") + return + end + local Attempt = Seed.CachedLevel[Path].Attempt + + local level = tonumber(Path:match("level0(%d)")) + DebugPrint("NEW LEVEL LOAD: Level " .. level) + + DebugPrint("Returning cached mission for Path " .. Path .. ", Attempt is " .. Attempt) + + local LoadFile = Seed.CachedLevel[Path].LoadFile[Attempt] + local InitFile = Seed.CachedLevel[Path].InitFile[Attempt] + for kk, vv in pairs(Seed.CachedLevel[Path].Globals[Attempt]) do + _G[kk] = vv + DebugPrint("Restoring global " .. kk .. " to value " .. tostring(vv), 3) + end + + LevelInit = InitFile + if Settings.DebugLevel >= 5 then + DebugPrint("Level Load File:\r\n" .. LoadFile) + DebugPrint("Level Init File:\r\n" .. InitFile) + end + Output(LoadFile) + + Attempt = Attempt + 1 + if Attempt > MAX_ATTEMPTS_LEVELS then + Attempt = 1 + end + Seed.CachedLevel[Path].Attempt = Attempt +end + +function Seed.HandleModulesMission(Path) + if Seed.CachedMission[Path] == nil then + DebugPrint("Request for Path " .. Path .. " was not seeded, falling back to normal generation") + return + end + local Attempt = Seed.CachedMission[Path].Attempt + + local level = tonumber(Path:match("level0(%d)")) + local prefix, mission = Path:match("([bsg]?[rm])(%d)l") + mission = tonumber(mission) + local misstype, missname + if prefix == "m" then + misstype = MissionType.Normal + missname = "Mission" + elseif prefix == "sr" then + misstype = MissionType.Race + missname = "Race" + elseif prefix == "bm" then + misstype = MissionType.BonusMission + missname = "Bonus Mission" + elseif prefix == "gr" then + misstype = MissionType.GamblingRace + missname = "Gambling Race" + else + error("unknown mission script type") + end + DebugPrint("NEW MISSION/RACE LOAD: Level " .. level .. ", " .. missname .. " " .. mission) + + DebugPrint("Returning cached mission for Path " .. Path .. ", Attempt is " .. Attempt) + + local LoadFile = Seed.CachedMission[Path].LoadFile[Attempt] + local InitFile = Seed.CachedMission[Path].InitFile[Attempt] + for kk, vv in pairs(Seed.CachedMission[Path].Globals[Attempt]) do + _G[kk] = vv + DebugPrint("Restoring global " .. kk .. " to value " .. tostring(vv), 3) + end + + MissionInit = InitFile + if Settings.DebugLevel >= 5 then + DebugPrint("Mission Load File:\r\n" .. LoadFile) + DebugPrint("Mission Init File:\r\n" .. InitFile) + end + Output(LoadFile) + + Attempt = Attempt + 1 + if Attempt > MAX_ATTEMPTS_MISSIONS then + Attempt = 1 + end + Seed.CachedMission[Path].Attempt = Attempt +end + +function Seed.HandleModulesSDMission(Path) + if Seed.CachedSDMission[Path] == nil then + DebugPrint("Request for Path " .. Path .. " was not seeded, falling back to normal generation") + return + end + local Attempt = Seed.CachedSDMission[Path].Attempt + + local level = tonumber(Path:match("level0(%d)")) + local mission = tonumber(Path:match("m(%d)sdl")) + DebugPrint("NEW SD LOAD: Level " .. level .. ", Mission " .. mission) + + DebugPrint("Returning cached mission for Path " .. Path .. ", Attempt is " .. Attempt) + + local LoadFile = Seed.CachedSDMission[Path].LoadFile[Attempt] + local InitFile = Seed.CachedSDMission[Path].InitFile[Attempt] + for kk, vv in pairs(Seed.CachedSDMission[Path].Globals[Attempt]) do + _G[kk] = vv + DebugPrint("Restoring global " .. kk .. " to value " .. tostring(vv), 3) + end + + LastLevel = nil + PlayerStats = nil + SDInit = InitFile + if Settings.DebugLevel >= 5 then + DebugPrint("SD Load File:\r\n" .. LoadFile) + DebugPrint("SD Init File:\r\n" .. InitFile) + end + Output(LoadFile) + + Attempt = Attempt + 1 + if Attempt > MAX_ATTEMPTS_MISSIONS then + Attempt = 1 + end + Seed.CachedSDMission[Path].Attempt = Attempt +end + +function Seed.Init() + if Settings.Seed == nil or Settings.Seed == "" then + local number = math.random(math.maxinteger) + Settings.Seed = Seed.Base64(string.pack("j", number)) + Seed.SeedRaw = number + DebugPrint("Generated a new seed: " .. Settings.Seed) + else + if (Settings.Seed:len() > 11) then + Alert("Your seed was longer than 11 characters, characters after this won't affect the seed or the randomness") + end + local raw = Seed.Base64dec(Settings.Seed) + if raw:len() < 16 then + raw = raw .. string.rep("\0", 16 - raw:len()) + end + Seed.SeedRaw = string.unpack("j", raw) + end + DebugPrint("Initialising RNG with Seed: " .. Seed.SeedRaw) + math.randomseed(Seed.SeedRaw) +end + +function Seed.AddSpoiler(f, ...) + Seed.Spoiler[#Seed.Spoiler + 1] = string.format(f, ...) +end + +function Seed.PrintSpoiler() + print("--- BEGIN SEED SPOILERS ---") + print(base64(table.concat(Seed.Spoiler, "\n"))) + print("--- END SPOILERS ---") +end diff --git a/Randomiser/meta.py b/Randomiser/meta.py new file mode 100644 index 0000000..16fc4c8 --- /dev/null +++ b/Randomiser/meta.py @@ -0,0 +1,20 @@ +import pygit2 +import os + +repo = pygit2.Repository("..") +branch_name = repo.head.shorthand +rev_id = repo.revparse_single('HEAD').short_id + +meta = open('Meta.ini', 'r') +meta_new = open('Meta.ini.tmp', 'w') + +for line in meta.readlines(): + if line.startswith('Version='): + meta_new.write("Version=git-{}-{}\n".format(branch_name, rev_id)) + else: + meta_new.write(line) + +meta.close() +meta_new.close() + +os.replace('Meta.ini.tmp', 'Meta.ini')