-- name: Factions -- description: Factions v1.0.1\nBy \\#B4E\\Snowy\n\n\\#dcdcdc\\This mod adds a fully functional faction system with many color factions to sm64coopdx.\n\nThe commands are:\n\n/faction - Joins a \\#ffff55\\color faction. \\#fff\\Valid colors are red, orange, yellow, green, blue, purple, pink, black, and white.\n\n/leavefaction - Leaves your current faction.\n\n/fc [msg] - Secretly message your faction teammates.\n\n/listfaction - Lists all active factions and online players.\n\nSpecial thanks to Dan, Kozmi, Jakz, and many others for playtesting. -- Unique network headers local PACKET_FACTION_CHAT = "FACTION_PRIVATE_CHAT" -- Prevent duplicate chat tracking local last_processed_msg = "" local last_processed_player = -1 -- Allowed factions list. local allowed_factions = { ["red"] = { tag = "\\#ff0000\\[RED]\\#ffffff\\ ", color = "\\#ff0000\\", raw_tag = "[RED] " }, ["blue"] = { tag = "\\#0000ff\\[BLUE]\\#ffffff\\ ", color = "\\#0000ff\\", raw_tag = "[BLUE] " }, ["green"] = { tag = "\\#00ff00\\[GREEN]\\#ffffff\\ ", color = "\\#00ff00\\", raw_tag = "[GREEN] " }, ["yellow"] = { tag = "\\#ffff00\\[YELLOW]\\#ffffff\\ ",color = "\\#ffff00\\", raw_tag = "[YELLOW] " }, ["pink"] = { tag = "\\#ffc0cb\\[PINK]\\#ffffff\\ ", color = "\\#ffc0cb\\", raw_tag = "[PINK] " }, ["purple"] = { tag = "\\#800080\\[PURPLE]\\#ffffff\\ ",color = "\\#800080\\", raw_tag = "[PURPLE] " }, ["orange"] = { tag = "\\#ffa500\\[ORANGE]\\#ffffff\\ ",color = "\\#ffa500\\", raw_tag = "[ORANGE] " }, ["black"] = { tag = "\\#aaaaaa\\[BLACK]\\#ffffff\\ ", color = "\\#aaaaaa\\", raw_tag = "[BLACK] " }, ["white"] = { tag = "\\#ffffff\\[WHITE]\\#ffffff\\ ", color = "\\#ffffff\\", raw_tag = "[WHITE] " } } -- Overrides overhead nametags function function on_nametags_render(playerIndex, pos) local faction_name = gPlayerSyncTable[playerIndex].faction if faction_name and faction_name ~= "" and faction_name ~= "none" then local faction_data = allowed_factions[faction_name] if faction_data then local base_name = gNetworkPlayers[playerIndex].name local custom_name = faction_data.color .. faction_data.raw_tag .. base_name return { name = custom_name } end end return nil end -- INTERCEPTS GLOBAL CHAT CHANNELS NATIVELY WITHOUT DUPLICATES function on_chat_message(m, message) local pIndex = m.playerIndex local faction_name = gPlayerSyncTable[pIndex].faction -- Anti-duplication check: if this exact message from this player was just processed, drop it if message == last_processed_msg and pIndex == last_processed_player then return false end if faction_name and faction_name ~= "" and faction_name ~= "none" then local faction_data = allowed_factions[faction_name] if faction_data then -- Skip if it's already got raw formatting tags in it if message:find(faction_data.raw_tag, 1, true) or message:find("\\[", 1) then return true end -- Set anti-duplication variables last_processed_msg = message last_processed_player = pIndex local player_name = gNetworkPlayers[pIndex].name -- Display custom text manually on this client machine [1] djui_chat_message_create(faction_data.tag .. faction_data.color .. player_name .. "\\#ffffff\\: " .. message) -- Suppress the original vanilla un-tagged message [1] return false end end return true end -- /faction command function on_faction_command(msg) local target_color = msg:gsub("%s+", ""):lower() if target_color == "" then djui_chat_message_create("HUH??? Please specify a color! Usage: /faction [color]") return true end if allowed_factions[target_color] then gPlayerSyncTable[0].faction = target_color mod_storage_save("saved_faction", target_color) djui_chat_message_create("You joined the " .. target_color:upper() .. " faction.") else djui_chat_message_create("Invalid choice! Choose: red, blue, green, yellow, pink, purple, orange, black, white.") end return true end -- /leavefaction command function on_leave_command(msg) local current_faction = gPlayerSyncTable[0].faction if not current_faction or current_faction == "" or current_faction == "none" then djui_chat_message_create("Error: You aren't even in a faction right now!") return true end gPlayerSyncTable[0].faction = "none" mod_storage_save("saved_faction", "none") djui_chat_message_create("You have left your faction. Your name tag has been reset.") return true end -- Rules function on_rules_command(msg) djui_chat_message_create("--- FACTION RULES ---") djui_chat_message_create("1. Don't hoard items from your team.") djui_chat_message_create("2. Stick together or else you might end up in a pickle.") djui_chat_message_create("3. Don't sabotage your teammates, that's just not nice.") djui_chat_message_create("4. DON'T BE RACIST TO OTHER FACTIONS.") djui_chat_message_create("--- If you're the host, feel free to change these. ---") return true end -- /listfaction command function on_list_faction_command(msg) djui_chat_message_create("--- ONLINE FACTIONS ---") local factions_populated = false for color_key, data in pairs(allowed_factions) do local member_names = "" for i = 0, (MAX_PLAYERS - 1) do if gNetworkPlayers[i] and gNetworkPlayers[i].connected then local player_fac = gPlayerSyncTable[i].faction if player_fac == color_key then if member_names == "" then member_names = gNetworkPlayers[i].name else member_names = member_names .. ", " .. gNetworkPlayers[i].name end end end end if member_names ~= "" then djui_chat_message_create(data.color .. color_key:upper() .. ": \\#ffffff\\" .. member_names) factions_populated = true end end if not factions_populated then djui_chat_message_create("No players are currently in a faction!") end return true end ----------------------------- -- EXPLICIT CUSTOM PACKETS -- ----------------------------- -- Private Faction Chat Command (/fc or /f) function on_faction_chat_command(msg) local my_faction = gPlayerSyncTable.faction if not my_faction or my_faction == "" or my_faction == "none" then djui_chat_message_create("Error: You must be in a faction to use faction chat!") return true end if msg == "" then djui_chat_message_create("Usage: /fc [message]") return true end local packet_data = { id = PACKET_FACTION_CHAT, faction = my_faction, message = msg } network_send(true, packet_data) local faction_data = allowed_factions[my_faction] local my_name = gNetworkPlayers.name djui_chat_message_create("\\#aaaaaa\\[FACTION]\\#ffffff\\ " .. faction_data.color .. my_name .. "\\#ffffff\\: " .. msg) return true end -- Handles private packets arriving from teammates function on_packet_receive(packet) if packet.id ~= PACKET_FACTION_CHAT then return end local local_faction = gPlayerSyncTable.faction local incoming_faction = packet.faction local incoming_msg = packet.message if not local_faction or local_faction == "none" or local_faction ~= incoming_faction then return end local sender_index = packet.playerIndex local sender_name = gNetworkPlayers[sender_index].name local faction_data = allowed_factions[incoming_faction] djui_chat_message_create("\\#aaaaaa\\[FACTION]\\#ffffff\\ " .. faction_data.color .. sender_name .. "\\#ffffff\\: " .. incoming_msg) end ----------------------------- -- Save and load stuff. function on_level_init() local saved_color = mod_storage_load("saved_faction") if saved_color and allowed_factions[saved_color] then gPlayerSyncTable[0].faction = saved_color else gPlayerSyncTable[0].faction = "none" mod_storage_save("saved_faction", "none") end end -- No PVP if you're in the same faction of the person you're attacking function on_pvp_attack(attacker_mario, victim_mario) local attacker_index = attacker_mario.playerIndex local victim_index = victim_mario.playerIndex local attacker_faction = gPlayerSyncTable[attacker_index].faction local victim_faction = gPlayerSyncTable[victim_index].faction if attacker_faction and victim_faction and attacker_faction ~= "" and attacker_faction ~= "none" and attacker_faction == victim_faction then return false end return true end -- Hook events hook_event(HOOK_ON_NAMETAGS_RENDER, on_nametags_render) hook_event(HOOK_ON_CHAT_MESSAGE, on_chat_message) hook_event(HOOK_ON_LEVEL_INIT, on_level_init) hook_event(HOOK_ALLOW_PVP_ATTACK, on_pvp_attack) hook_event(HOOK_ON_PACKET_RECEIVE, on_packet_receive) -- Hook commands hook_chat_command("faction", "[color] - Choose your color faction.", on_faction_command) hook_chat_command("leavefaction", "- Leaves your color faction.", on_leave_command) hook_chat_command("rules", "- Lists rules for factions.", on_rules_command) hook_chat_command("fc", "[message] - Secretly message your faction.", on_faction_chat_command) hook_chat_command("f", "[message] - Secretly message your faction.", on_faction_chat_command) hook_chat_command("listfaction", "- Lists all active color factions and players.", on_list_faction_command) hook_chat_command("lf", "- Lists all active color factions and players.", on_list_faction_command)