// Generate a SOC file with Lua. Well, almost - the end user has to change the file // extension of the resulting text file from .txt to .soc themselves. // The mapheaderinfo "table" isn't a normal table... hecc. if not SOCGen then rawset(_G, "SOCGen", {}) end SOCGen.name = "SOCGen" SOCGen.fullname = "SOC Generator" SOCGen.ver = "Dependant-O-s (1.01a)" SOCGen.author = "TheOneGoofAli" SOCGen.mapheaderextra = {} // Plugin run toggle. local SOCGenPluginRun = CV_RegisterVar({ name = "socgenpluginrun", defaultvalue = 1, flags = CV_SHOWMODIF, PossibleValue = CV_OnOff }) // Just extra information printing. local SOCGenDebug = CV_RegisterVar({ name = "socgendebug", defaultvalue = 0, flags = CV_SHOWMODIFONETIME, PossibleValue = CV_OnOff }) // Restrict use to admin/host only by default. local SOCGenExecAdminOnly = CV_RegisterVar({ name = "socgenexecadminlock", defaultvalue = 1, flags = CV_NETVAR | CV_SHOWMODIF, PossibleValue = CV_OnOff }) // Check if item is not nil or empty. local function ProcessEntry(item) if item == nil or tostring(item) == "" then return false else return true end end // Read TOL and return string. Some maps might have multiple of these assigned... weird. local function ReadTOL(mapid) if (mapheaderinfo[mapid].typeoflevel & TOL_RACE) == 8 then return "Race" elseif (mapheaderinfo[mapid].typeoflevel & TOL_MATCH) == 16 then return "Battle" elseif (mapheaderinfo[mapid].typeoflevel & TOL_SP) == 1 then return "Singleplayer" else return "Unknown/Other" end end // Note: NoZone is checked via the LF_NOZONE level flag. local function ReadNoZone(mapid) if (mapheaderinfo[mapid].levelflags & LF_NOZONE) == 16 then return true end end // Hidden/hellmap? local function ReadHidden(mapid) if (mapheaderinfo[mapid].menuflags & LF2_HIDEINMENU) == 1 then return true else return end end // It was taller than me! All-- or, well, most of map stuff. local function ProcessMapInfo(mapid, file, detailed, p) if file == nil then error("Failed I/O access!") return end if mapheaderinfo[mapid] == nil then return end detailed = $ or false // Starting section for level info. if SOCGenDebug.value == 1 then CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." Reading information about map "..mapid.." / "..MUtils.inttoext(mapid)) end file:write("Level "..MUtils.inttoext(mapid), "\n") // As the mapheaderinfo "table" isn't a normal table Lua can access... we'll have to do it this way. if ProcessEntry(mapheaderinfo[mapid].lvlttl) then file:write("LevelName = "..mapheaderinfo[mapid].lvlttl, "\n") end if ProcessEntry(mapheaderinfo[mapid].subttl) then file:write("SubTitle = "..mapheaderinfo[mapid].subttl, "\n") end if ReadNoZone(mapid) then file:write("NoZone = True", "\n") end if ProcessEntry(mapheaderinfo[mapid].zonttl) then file:write("ZoneTitle = "..mapheaderinfo[mapid].zonttl, "\n") end if ProcessEntry(mapheaderinfo[mapid].actnum) then file:write("Act = "..mapheaderinfo[mapid].actnum, "\n") end if ProcessEntry(mapheaderinfo[mapid].typeoflevel) then file:write("TypeOfLevel = "..ReadTOL(mapid), "\n") end if ProcessEntry(mapheaderinfo[mapid].nextlevel) and detailed then file:write("NextLevel = "..mapheaderinfo[mapid].nextlevel, "\n") end if ProcessEntry(mapheaderinfo[mapid].musname) then file:write("Music = "..mapheaderinfo[mapid].musname, "\n") end if detailed then // big brain. if ProcessEntry(mapheaderinfo[mapid].mustrack) then file:write("MusicTrack = "..mapheaderinfo[mapid].mustrack, "\n") end if ProcessEntry(mapheaderinfo[mapid].muspos) then file:write("MusicPos = "..mapheaderinfo[mapid].muspos, "\n") end if ProcessEntry(mapheaderinfo[mapid].musinterfadeout) then file:write("MusicInterFadeOut = "..mapheaderinfo[mapid].musinterfadeout, "\n") end if ProcessEntry(mapheaderinfo[mapid].forcecharacter) then file:write("ForceCharacter = "..mapheaderinfo[mapid].forcecharacter, "\n") end if ProcessEntry(mapheaderinfo[mapid].weather) then file:write("Weather = "..mapheaderinfo[mapid].weather, "\n") end if ProcessEntry(mapheaderinfo[mapid].skynum) then file:write("SkyNum = "..mapheaderinfo[mapid].skynum, "\n") end if ProcessEntry(mapheaderinfo[mapid].skybox_scalex) then file:write("SkyboxScaleX = "..mapheaderinfo[mapid].skybox_scalex, "\n") end if ProcessEntry(mapheaderinfo[mapid].skybox_scaley) then file:write("SkyboxScaleY = "..mapheaderinfo[mapid].skybox_scaley, "\n") end if ProcessEntry(mapheaderinfo[mapid].skybox_scalez) then file:write("SkyboxScaleZ = "..mapheaderinfo[mapid].skybox_scalez, "\n") end // These commented out ones kinda result in messy outputs... //if ProcessEntry(mapheaderinfo[mapid].interscreen) then file:write("InterScreen = "..mapheaderinfo[mapid].interscreen, "\n") end //if ProcessEntry(mapheaderinfo[mapid].runsoc) then file:write("RunSOC = "..mapheaderinfo[mapid].runsoc, "\n") end //if ProcessEntry(mapheaderinfo[mapid].scriptname) then file:write("ScriptName = "..mapheaderinfo[mapid].scriptname, "\n") end if ProcessEntry(mapheaderinfo[mapid].precutscenenum) then file:write("PreCutsceneNum = "..mapheaderinfo[mapid].precutscenenum, "\n") end if ProcessEntry(mapheaderinfo[mapid].cutscenenum) then file:write("CutsceneNum = "..mapheaderinfo[mapid].cutscenenum, "\n") end if ProcessEntry(mapheaderinfo[mapid].countdown) then file:write("Countdown = "..mapheaderinfo[mapid].countdown, "\n") end if ProcessEntry(mapheaderinfo[mapid].palette) then file:write("Palette = "..mapheaderinfo[mapid].palette, "\n") end end if ProcessEntry(mapheaderinfo[mapid].numlaps) then file:write("NumLaps = "..mapheaderinfo[mapid].numlaps, "\n") end if detailed then // ...yes, I am following the order of the stuff listed for the "mapheader_t". if ProcessEntry(mapheaderinfo[mapid].unlockrequired) then file:write("Unlockable = "..mapheaderinfo[mapid].unlockrequired, "\n") end if ProcessEntry(mapheaderinfo[mapid].levelselect) then file:write("LevelSelect = "..mapheaderinfo[mapid].levelselect, "\n") end // Not used. // if ProcessEntry(mapheaderinfo[mapid].bonustype) then file:write("BonusType = "..mapheaderinfo[mapid].bonustype, "\n") end // if ProcessEntry(mapheaderinfo[mapid].saveoverride) then file:write("SaveOverride = "..mapheaderinfo[mapid].saveoverride, "\n") end end if ReadHidden(mapid) then file:write("Hidden = True", "\n") end // Hellmap? if ProcessEntry(mapheaderinfo[mapid].mobj_scale) and mapheaderinfo[mapid].mobj_scale != FRACUNIT then file:write("MobjScale = "..mapheaderinfo[mapid].mobj_scale, "\n") end local mapheaderextra = SOCGen.mapheaderextra if #mapheaderextra > 0 and SOCGenPluginRun.value == 1 then for v = 1, #mapheaderextra do local result = mapheaderextra[v](mapid) if result != nil and result != "" then // Neither nil or empty. if type(result) == "table" then // For each string present, write it out. for i = 1, #result do file:write(result[i], "\n") end else file:write(result, "\n") end // ...or just write the returned content. end end end end // Write plugins active to open file handle. local function WritePluginsActive(table, file) if #table > 0 then for i = 1, #table file:write("# > "..table[i](nil, true), "\n") end file:write("\n") end end // Perform file access and write stuff. local function WriteThatSOC(thetable, p, detailed) if p != consoleplayer then return end // No io.openlocal... workaround. local file = io.open("socgen.txt", "w+") // Open file... file:write("# Generated with SOCGen "..SOCGen.ver.." by TheOneGoofAli.", "\n", "# Please change the file extension of this to .soc before use!", "\n") local plugintable = SOCGen.mapheaderextra if type(plugintable) == "table" and #plugintable > 0 then file:write("# Plugins active at time of generation:", "\n") WritePluginsActive(plugintable, file) end for k, v in ipairs(thetable) do ProcessMapInfo(v[4], file, detailed, p) // Pass mapID and file handle. if k != #thetable then file:write("\n") end // Seperate our levels. end file:close() // Finish. CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." Write successful.") end // Do we have extensions to our script loaded? local function SOCGenListPlugins(p) local plugins = SOCGen.mapheaderextra if plugins and #plugins > 0 then CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." Currently loaded extensions:") for i = 1, #plugins do CONS_Printf(p, plugins[i](nil, true)) end else CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." No extensions are loaded.") end end // The Main. local function Main(p, arg1, arg2, arg3, arg4) if p != consoleplayer then return end if SOCGenExecAdminOnly.value == 1 and not (IsPlayerAdmin(p) or p == server) then // Admin-only? CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." Insufficient privileges.") return end arg1, arg2, arg3, arg4 = $ or "all", $ or "", $ or "", $ or "" arg1, arg2, arg3, arg4 = arg1:lower(), arg2:lower(), arg3:lower(), arg4:lower() if arg1 == "plugin" or arg1 == "plugins" or arg1 == "extensions" then // We're doing plugin check instead. SOCGenListPlugins(p) return end if not MUtils then error("MapUtils not loaded. Please load MapUtils first.") end local gmode, searchterm, detailed = "all", "", false if arg1 == "race" or arg1 == "battle" or arg1 == "singleplayer" or arg1 == "all" then gmode = arg1 end // Set gametype. Fallback to everything. if arg2 != "" then searchterm = arg2 end // Do we have a search to do? if arg3 == "1" or arg3 == "true" or arg3 == "detailed" then detailed = true end // ...increase output? if searchterm != "" then CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." Performing search of '"..searchterm.."' with MapUtils...") else CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." Using MapUtils to gather map IDs...") end local mappy = MUtils.maplist(searchterm, gmode) // Grab resulting table. if #mappy > 0 then CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." Initiating write of SOC to 'luafiles/socgen.txt'...") WriteThatSOC(mappy, p, detailed) else CONS_Printf(p, "\x82"..SOCGen.name..":".."\x80".." No maps were found with provided settings.") end end // Just this one command. COM_AddCommand("SOCGen", Main) // We loaded. print("\x82"..SOCGen.fullname.." "..SOCGen.ver.."\x80".." by ".."\x87"..SOCGen.author.."\x80") // Plugin integration from PluginExample. // You can return a single string (Lua.testval = 1) or a table of strings if there's // multiple "Lua.customval" for SOCGen to use. In this example, we'll return a table // of strings which will be unpacked by the script. // Listing it is SOCGenDaytonaKart(nil, true). local function SOCGenDaytonaKart(mapid, name, p) if name then return "Daytona Kart Detection" end local outtable = {} if daytonakart and maptimes then // The "and" is important here - we want to see if the value is neither nil OR empty. if mapheaderinfo[mapid].arcadetime != nil and mapheaderinfo[mapid].arcadetime != "" then table.insert(outtable, "lua.arcadetime = "..mapheaderinfo[mapid].arcadetime) end if mapheaderinfo[mapid].arcadebonus != nil and mapheaderinfo[mapid].arcadebonus != "" then table.insert(outtable, "lua.arcadebonus = "..mapheaderinfo[mapid].arcadebonus) end if mapheaderinfo[mapid].noextension != nil and mapheaderinfo[mapid].noextension != "" then table.insert(outtable, "lua.noextension = "..mapheaderinfo[mapid].noextension) end if mapheaderinfo[mapid].arcadeboss != nil and mapheaderinfo[mapid].arcadeboss != "" then table.insert(outtable, "lua.arcadeboss = "..mapheaderinfo[mapid].arcadeboss) end if #outtable > 0 then return outtable else return end // If there's actually something, return the table. end end table.insert(SOCGen.mapheaderextra, SOCGenDaytonaKart)