-- name: Character Select Randomizer -- description: character select randomizer \nCreated by wereyoshi. -- pausable: true -- category: cs gGlobalSyncTable.rerolloncoincollect = false --whether player's character is rerolled on coin collection gGlobalSyncTable.rerollonlevelinit = true --whether player's character is rerolled on entering a level gGlobalSyncTable.rerollonhit = false --whether player's character is rerolled on being hit local charmax = 0 local inittable = false local modsupporthelperfunctions = {} --local references to functions from other mods local servermodsync = false local currcharacterindex = 0 local currcharactercostume = 1 local charactertable = {0} local charmax local costumemaxtable = {} local externalmodmanagecharacter = false local altcharacter_reroll = false local version = "1.0.0" -- the current version of the mod local character_reroll local prevhurtcounter = 0 local touchedflame = false local bool_to_str = {[false] = "\\#A02200\\off\\#ffffff\\",[true] = "\\#00C7FF\\on\\#ffffff\\"} --table for converting boolean into string local hookupdate --determines what happens on level start local function on_level_init() if inittable == false then charactertable = _G.charSelect.character_get_full_table() for key,value in pairs(charactertable)do costumemaxtable[key] = #(charactertable[key]) end charmax = #charactertable inittable = true end if gGlobalSyncTable.rerollonlevelinit then character_reroll() end end ---@param m MarioState ---@param o Object ---@param interactType InteractionType ---@param interactValue boolean --this function is for mario interacting with objects. local function on_interact(m,o,interactType,interactValue) if (interactType == INTERACT_COIN) and (gGlobalSyncTable.rerolloncoincollect) then character_reroll() elseif (interactType == INTERACT_FLAME) and (gGlobalSyncTable.rerollonhit) then local burningaction = {[ACT_BURNING_JUMP] = true,[ACT_BURNING_FALL] = true} if burningaction[m.action] == true and (not touchedflame) and ((m.flags & MARIO_METAL_CAP) == 0) then touchedflame = true character_reroll() end end end ---@param m MarioState --Called once per player per frame at the end of a mario update local function mario_update(m) if m.playerIndex ~= 0 then return end if m.hurtCounter ~= prevhurtcounter then if (m.hurtCounter > prevhurtcounter) and (gGlobalSyncTable.rerollonhit) then character_reroll() end prevhurtcounter = m.hurtCounter end if touchedflame then local burningaction = {[ACT_BURNING_JUMP] = true,[ACT_BURNING_FALL] = true,[ACT_BURNING_GROUND] = true} if burningaction[m.action] ~= true then touchedflame = false end end end --function used for built in support for some external mods local function modsupport() if _G.charSelect ~= nil then --if the character select mod is on modsupporthelperfunctions.charSelect = _G.charSelect --local reference for _G.charSelect modsupporthelperfunctions.charSelect.credit_add(string.format("character select randomizer version %s", version),"wereyoshi","mod maker") modsupporthelperfunctions.charselectoptions = {} modsupporthelperfunctions.charselectoptions.localmodeltogglepos = modsupporthelperfunctions.charSelect.optionTableRef.localModels --for char select versions 1.1 and up local csversiontable = modsupporthelperfunctions.charSelect.version_get_full() if (csversiontable.major > 15) or ((csversiontable.major == 15) and (csversiontable.minor > 0)) then --check for update with character_set_current_number getting second parameter --randomily changes the current character to another one character_reroll = function() if type(altcharacter_reroll) == "function" then altcharacter_reroll() return end currcharacterindex = math.random(1,charmax) currcharactercostume = math.random(costumemaxtable[currcharacterindex]) end ---Called once per frame hookupdate = function() if (externalmodmanagecharacter == true) or (inittable == false) then return end if (modsupporthelperfunctions.charSelect.get_options_status(modsupporthelperfunctions.charselectoptions.localmodeltogglepos) == 0) then modsupporthelperfunctions.charSelect.set_options_status(modsupporthelperfunctions.charselectoptions.localmodeltogglepos,1) elseif (currcharacterindex ~= modsupporthelperfunctions.charSelect.character_get_current_number()) or (currcharactercostume ~= modsupporthelperfunctions.charSelect.character_get_current_costume()) then modsupporthelperfunctions.charSelect.character_set_current_number(currcharacterindex,currcharactercostume) end end else log_to_console(string.format("character select version %s is older than the supported version for character randomizer please update at https://github.com/Squishy6094/character-select-coop/releases ",modsupporthelperfunctions.charSelect.version_get()),1) --randomily changes the current character to another one character_reroll = function() if type(altcharacter_reroll) == "function" then altcharacter_reroll() return end currcharacterindex = math.random(1,charmax) currcharactercostume = math.random(costumemaxtable[currcharacterindex]) end ---Called once per frame hookupdate = function() if (externalmodmanagecharacter == true) or (inittable == false) then return end if (modsupporthelperfunctions.charSelect.get_options_status(modsupporthelperfunctions.charselectoptions.localmodeltogglepos) == 0) then modsupporthelperfunctions.charSelect.set_options_status(modsupporthelperfunctions.charselectoptions.localmodeltogglepos,1) elseif (currcharacterindex ~= modsupporthelperfunctions.charSelect.character_get_current_number()) then modsupporthelperfunctions.charSelect.character_set_current_number(currcharacterindex) end end end hook_event(HOOK_ON_LEVEL_INIT, on_level_init) -- Called when the level is initialized hook_event(HOOK_UPDATE, hookupdate) -- hook that is called once per frame hook_event(HOOK_ON_INTERACT, on_interact) --Called before mario interacts with an object, return true to allow the interaction hook_event(HOOK_MARIO_UPDATE, mario_update) --Called once per player per frame at the end of a mario update else log_to_console(string.format("the character select mod was not found. \n This mod relies on the character select mod to function which can be found at https://github.com/Squishy6094/character-select-coop/releases \n character select randomizer mod version is %s",version), 2) end if _G.charselectnuzlockeapi ~= nil then modsupporthelperfunctions.charselectnuzlockeapi = _G.charselectnuzlockeapi modsupporthelperfunctions.charselectnuzlockeinitialized = false modsupporthelperfunctions.charselectrandomizerapi.othermodhandlecharacter() modsupporthelperfunctions.charselectnuzlockeapi.on_nuzlocketableupdate(function() modsupporthelperfunctions.livingtable,modsupporthelperfunctions.livingtablesize = modsupporthelperfunctions.charselectnuzlockeapi.get_livingcharactertable() if modsupporthelperfunctions.charselectnuzlockeinitialized == false then modsupporthelperfunctions.charselectnuzlockeinitialized = true character_reroll() end end) modsupporthelperfunctions.charselectrandomizerapi.customcharacterrerollfunction(function() if (modsupporthelperfunctions.charselectnuzlockeinitialized == false) or (modsupporthelperfunctions.livingtablesize == 0) then return end local charnumindex local cosnumindex local randomindex = math.random(modsupporthelperfunctions.livingtablesize) charnumindex = modsupporthelperfunctions.livingtable[randomindex][1] cosnumindex = modsupporthelperfunctions.livingtable[randomindex][2] modsupporthelperfunctions.charselectnuzlockeapi.set_nuzlockecharacter(charnumindex,cosnumindex) end) end end --- @param m MarioState --Called when a player connects local function on_player_connected(m) -- only run on server if not network_is_server() then return end if servermodsync == false then modsupport() servermodsync = true if (mod_storage_load("rerolloncoincollect") == nil) then mod_storage_save_bool("rerollonlevelinit", gGlobalSyncTable.rerollonlevelinit) mod_storage_save_bool("rerolloncoincollect", gGlobalSyncTable.rerolloncoincollect) mod_storage_save_bool("rerollonhit", gGlobalSyncTable.rerollonhit) else gGlobalSyncTable.rerollonlevelinit = mod_storage_load_bool("rerollonlevelinit") gGlobalSyncTable.rerolloncoincollect = mod_storage_load_bool("rerolloncoincollect") gGlobalSyncTable.rerollonhit = mod_storage_load_bool("rerollonhit") end end end --Called when the local player finishes the join process (if the player isn't the host) local function on_join() if servermodsync == false then modsupport() servermodsync = true end end hook_event(HOOK_ON_PLAYER_CONNECTED, on_player_connected) -- hook for player joining hook_event(HOOK_JOINED_GAME, on_join) -- Called when the local player finishes the join process (if the player isn't the host) --- @param msg string --this function toggles rerolling on coin collection local function rerolloncoincollect_command(msg) if not network_is_server() then djui_chat_message_create('Only the host can change this setting!') return true end local m = string.lower(msg) if m == 'on' then djui_chat_message_create('reroll character on coin collect is \\#00C7FF\\on\\#ffffff\\!') gGlobalSyncTable.rerolloncoincollect = true return true elseif m == 'off' then djui_chat_message_create('reroll character on coin collect is \\#A02200\\off\\#ffffff\\!') gGlobalSyncTable.rerolloncoincollect = false return true else return false end end --- @param msg string --this function toggles rerolling on coin collection local function rerollonlevelinit_command(msg) if not network_is_server() then djui_chat_message_create('Only the host can change this setting!') return true end local m = string.lower(msg) if m == 'on' then djui_chat_message_create('reroll character on level start is \\#00C7FF\\on\\#ffffff\\!') gGlobalSyncTable.rerollonlevelinit = true return true elseif m == 'off' then djui_chat_message_create('reroll character on level start is \\#A02200\\off\\#ffffff\\!') gGlobalSyncTable.rerollonlevelinit = false return true else return false end end --- @param msg string --this function toggles rerolling on coin collection local function rerollonhit_command(msg) if not network_is_server() then djui_chat_message_create('Only the host can change this setting!') return true end local m = string.lower(msg) if m == 'on' then djui_chat_message_create('reroll character on hit is \\#00C7FF\\on\\#ffffff\\!') gGlobalSyncTable.rerollonhit = true return true elseif m == 'off' then djui_chat_message_create('reroll character on hit is \\#A02200\\off\\#ffffff\\!') gGlobalSyncTable.rerollonhit = false return true else return false end end --- @param msg string --this is the function for save server settings or loading them local function characterselectrandomizerconfig_command(msg) local m = string.lower(msg) if m == 'save' then mod_storage_save_bool("rerollonlevelinit", gGlobalSyncTable.rerollonlevelinit) mod_storage_save_bool("rerolloncoincollect", gGlobalSyncTable.rerolloncoincollect) mod_storage_save_bool("rerollonhit", gGlobalSyncTable.rerollonhit) djui_chat_message_create('current character select randomizer server config saved') return true elseif m == 'load' then if not network_is_server() and not network_is_moderator then djui_chat_message_create('Only the host or a mod can change this setting!') return true else gGlobalSyncTable.rerollonlevelinit = mod_storage_load_bool("rerollonlevelinit") gGlobalSyncTable.rerolloncoincollect = mod_storage_load_bool("rerolloncoincollect") gGlobalSyncTable.rerollonhit = mod_storage_load_bool("rerollonhit") djui_chat_message_create('character select randomizer server server config loaded') return true end elseif m == 'printserver' then djui_chat_message_create(string.format("This server is using version %s of the character select randomizer mod with the following settings", version)) djui_chat_message_create(string.format("rerollonlevelinit is %s",bool_to_str[gGlobalSyncTable.rerollonlevelinit])) djui_chat_message_create(string.format("rerolloncoincollect is %s",bool_to_str[gGlobalSyncTable.rerolloncoincollect])) djui_chat_message_create(string.format("rerollonhit is %s",bool_to_str[gGlobalSyncTable.rerollonhit])) return true else return false end end if hook_mod_menu_text ~= nil then hook_mod_menu_text(string.format("mod version %s",version)) end hook_mod_menu_button("toggle reroll character on coin collection",function(index) local s if gGlobalSyncTable.rerolloncoincollect then s = 'off' else s = 'on' end rerolloncoincollect_command(s) end) hook_mod_menu_button("toggle reroll character on level init",function(index) local s if gGlobalSyncTable.rerollonlevelinit then s = 'off' else s = 'on' end rerollonlevelinit_command(s) end) hook_mod_menu_button("toggle reroll character on hit",function(index) local s if gGlobalSyncTable.rerollonhit then s = 'off' else s = 'on' end rerollonhit_command(s) end) hook_mod_menu_button("print character select randomizer server config",function(index) characterselectrandomizerconfig_command('printserver') end) hook_mod_menu_button("save current character select randomizer config",function(index) characterselectrandomizerconfig_command('save') end) hook_mod_menu_button("load character select randomizer config",function(index) characterselectrandomizerconfig_command('load') end) hook_chat_command('rerollcharacteroncoincollect', "[on|off] turn rerolling character on coin collection \\#00C7FF\\on \\#ffffff\\or \\#A02200\\off \\#ffffff\\", rerolloncoincollect_command) hook_chat_command('rerollcharacteronlevelinit', "[on|off] turn rerolling character on level init \\#00C7FF\\on \\#ffffff\\or \\#A02200\\off \\#ffffff\\", rerollonlevelinit_command) hook_chat_command('rerollcharacteronhit', "[on|off] turn rerolling character on hit \\#00C7FF\\on \\#ffffff\\or \\#A02200\\off \\#ffffff\\", rerollonhit_command) hook_chat_command('characterselectrandomizerconfig', "[save|load|printserver] to save the current character select randomizer settings to a file or load them (loading only works if used by a moderator or the server)", characterselectrandomizerconfig_command) _G.charselectrandomizerapi = { --this allows another mod to disable character select randomizer stopping character switching othermodhandlecharacter = function() externalmodmanagecharacter = true end, --- @param func function function to replace the default reroll function ---this allows other mods to provide their own character reroll function customcharacterrerollfunction = function(func) altcharacter_reroll = func end, get_version = function() return version end, --allows another mod to force a character reroll forcereroll = function() character_reroll() end } modsupporthelperfunctions.charselectrandomizerapi = _G.charselectrandomizerapi