From bb0ea7496174b9094e20c93c7083a800b02f2428 Mon Sep 17 00:00:00 2001 From: Evil Factory <36804725+evilfactory@users.noreply.github.com> Date: Wed, 14 Apr 2021 01:00:56 -0300 Subject: [PATCH] example --- .../ServerSource/Lua/LuaClasses.cs | 49 +- .../ServerSource/Lua/LuaScriptLoader.cs | 12 +- .../ServerSource/Lua/LuaSetup.cs | 69 +-- .../ServerSource/Networking/GameServer.cs | 5 +- Example/Lua/traitormod/autorun/traitormod.lua | 493 ++++++++++++++++++ .../Lua/traitormod/autorun/traitorship.lua | 129 +++++ Example/Lua/traitormod/traitorconfig.lua | 36 ++ Example/Lua/traitormod/util.lua | 116 +++++ 8 files changed, 851 insertions(+), 58 deletions(-) create mode 100644 Example/Lua/traitormod/autorun/traitormod.lua create mode 100644 Example/Lua/traitormod/autorun/traitorship.lua create mode 100644 Example/Lua/traitormod/traitorconfig.lua create mode 100644 Example/Lua/traitormod/util.lua diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs index 8ea9302c8..65ef51feb 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaClasses.cs @@ -37,6 +37,11 @@ namespace Barotrauma return values; } + public static CharacterInfo CreateCharacterInfo(string speciesName, string name = "", JobPrefab jobPrefab = null, string ragdollFileName = null, int variant = 0, Rand.RandSync randSync = Rand.RandSync.Unsynced) + { + return new CharacterInfo(speciesName, name, jobPrefab, ragdollFileName, variant, randSync); + } + public static void SetClientCharacter(Client client, Character character) { GameMain.Server.SetClientCharacter(client, character); @@ -65,10 +70,11 @@ namespace Barotrauma } - public static void StartGame() + public static void SetSpectatorPos(Client client, Vector2 pos) { - GameMain.Server.StartGame(); + client.SpectatePos = pos; } + } public class LuaGame @@ -89,9 +95,9 @@ namespace Barotrauma GameMain.Server.SendChatMessage(msg, messageType, sender, character); } - public static void SendTraitorMessage(Client client, string msg, TraitorMessageType type) + public static void SendTraitorMessage(Client client, string msg, string missionid, TraitorMessageType type) { - GameMain.Server.SendTraitorMessage(client, msg, "", type); + GameMain.Server.SendTraitorMessage(client, msg, missionid, type); } public static void SendDirectChatMessage(string sendername, string text, Character sender, ChatMessageType messageType = ChatMessageType.Private, Client client = null) @@ -163,7 +169,7 @@ namespace Barotrauma { if (CharacterPrefab.FindBySpeciesName(name) != null) { - Character.Create(name, spawnPosition, ToolBox.RandomSeed(8)); + spawnedCharacter = Character.Create(name, spawnPosition, ToolBox.RandomSeed(8)); } } @@ -212,6 +218,12 @@ namespace Barotrauma { DebugConsole.ExecuteCommand(command); } + + + public static void StartGame() + { + GameMain.Server.StartGame(); + } } @@ -251,6 +263,17 @@ namespace Barotrauma { return random.Next(min, max); } + + public float RangeFloat(float min, float max) + { + double range = (double)max - (double)min; + double sample = random.NextDouble(); + double scaled = (sample * range) + min; + float f = (float)scaled; + + return f; + } + } // hooks: @@ -264,9 +287,9 @@ namespace Barotrauma public class LuaHook { - public Script env; + public LuaSetup env; - public LuaHook(Script e) + public LuaHook(LuaSetup e) { env = e; } @@ -310,7 +333,7 @@ namespace Barotrauma { try { - var result = env.Call(hf.function, args); + var result = env.lua.Call(hf.function, args); if (result.IsNil() == false) { return result; @@ -318,15 +341,7 @@ namespace Barotrauma } catch (Exception e) { - if (e is InterpreterException) - { - - Console.WriteLine(((InterpreterException)e).DecoratedMessage); - } - else - { - Console.WriteLine(e.ToString()); - } + env.HandleLuaException(e); } } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaScriptLoader.cs b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaScriptLoader.cs index fb2f93769..6947e31d1 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaScriptLoader.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaScriptLoader.cs @@ -37,7 +37,7 @@ namespace Barotrauma if (s.EndsWith(".lua")) { - Console.WriteLine(s); + lua.PrintMessage(s); try { @@ -45,15 +45,7 @@ namespace Barotrauma } catch (Exception e) { - if (e is InterpreterException) - { - - Console.WriteLine(((InterpreterException)e).DecoratedMessage); - } - else - { - Console.WriteLine(e.ToString()); - } + lua.HandleLuaException(e); } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaSetup.cs b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaSetup.cs index 1cd65f9dc..48ada239d 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaSetup.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Lua/LuaSetup.cs @@ -17,6 +17,31 @@ namespace Barotrauma public LuaHook hook; public LuaGame game; + public void HandleLuaException(Exception ex) + { + if(ex is InterpreterException) + { + PrintMessage(((InterpreterException)ex).DecoratedMessage); + } + else + { + PrintMessage(ex.ToString()); + } + } + + public void PrintMessage(object message) + { + Console.WriteLine(message.ToString()); + if (GameMain.Server != null) + { + foreach (var c in GameMain.Server.ConnectedClients) + { + GameMain.Server.SendDirectChatMessage(message.ToString(), c, ChatMessageType.Console); + GameServer.Log("[LUA] " + message.ToString(), ServerLog.MessageType.ServerMessage); + } + } + } + public void DoString(string code) { try @@ -25,15 +50,7 @@ namespace Barotrauma } catch (Exception e) { - if (e is InterpreterException) - { - - Console.WriteLine(((InterpreterException)e).DecoratedMessage); - } - else - { - Console.WriteLine(e.ToString()); - } + HandleLuaException(e); } } @@ -46,15 +63,7 @@ namespace Barotrauma } catch (Exception e) { - if (e is InterpreterException) - { - - Console.WriteLine(((InterpreterException)e).DecoratedMessage); - } - else - { - Console.WriteLine(e.ToString()); - } + HandleLuaException(e); } } @@ -66,27 +75,24 @@ namespace Barotrauma } catch (Exception e) { - if (e is InterpreterException) - { - - Console.WriteLine(((InterpreterException)e).DecoratedMessage); - } - else - { - Console.WriteLine(e.ToString()); - } + HandleLuaException(e); } } public LuaSetup() { - Console.WriteLine("Lua!"); + PrintMessage("Lua!"); LuaScriptLoader luaScriptLoader = new LuaScriptLoader(this); LuaCustomConverters.RegisterAll(); + UserData.RegisterType(); + UserData.RegisterType(); + UserData.RegisterType(); + UserData.RegisterType(); + UserData.RegisterType(); UserData.RegisterType(); UserData.RegisterType(); UserData.RegisterType(); @@ -107,12 +113,15 @@ namespace Barotrauma UserData.RegisterType(); UserData.RegisterType(); UserData.RegisterType(); + lua = new Script(CoreModules.Preset_SoftSandbox | CoreModules.LoadMethods); + lua.Options.DebugPrint = PrintMessage; + lua.Options.ScriptLoader = luaScriptLoader; - hook = new LuaHook(lua); + hook = new LuaHook(this); game = new LuaGame(this); lua.Globals["Player"] = new LuaPlayer(); @@ -132,6 +141,8 @@ namespace Barotrauma lua.Globals["Vector2"] = UserData.CreateStatic(); lua.Globals["Vector3"] = UserData.CreateStatic(); lua.Globals["PositionType"] = UserData.CreateStatic(); + lua.Globals["JobPrefab"] = UserData.CreateStatic(); + lua.Globals["TraitorMessageType"] = UserData.CreateStatic(); foreach (string d in Directory.GetDirectories("Lua")) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 564d935ed..71c6feec8 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -2363,8 +2363,6 @@ namespace Barotrauma.Networking Log("Round started.", ServerLog.MessageType.ServerMessage); - GameMain.Lua.hook.Call("roundStart", new MoonSharp.Interpreter.DynValue[] { }); - gameStarted = true; initiatedStartGame = false; @@ -2374,6 +2372,9 @@ namespace Barotrauma.Networking roundStartTime = DateTime.Now; + GameMain.Lua.hook.Call("roundStart", new MoonSharp.Interpreter.DynValue[] { }); + + yield return CoroutineStatus.Success; } diff --git a/Example/Lua/traitormod/autorun/traitormod.lua b/Example/Lua/traitormod/autorun/traitormod.lua new file mode 100644 index 000000000..aecadd05a --- /dev/null +++ b/Example/Lua/traitormod/autorun/traitormod.lua @@ -0,0 +1,493 @@ +local traitormod = {} +traitormod.peoplePercentages = {} + +traitormod.roundtraitors = {} +traitormod.selectedCodeResponses = {} +traitormod.selectedCodePhrases = {} + +traitormod.enabled = true +traitormod.traitorShipEnabled = true +traitormod.roundGamemode = "" + +local traitorAssignDelay = 0 +local traitorsAssigned = true +local warningClients = {} + +Game.OverrideTraitors(true) -- shutup old traitors + +local config = dofile("lua/traitormod/traitorconfig.lua") +local util = dofile("lua/traitormod/util.lua") + +traitormod.config = config + +traitormod.setPercentage = function(client, amount) + if client == nil then return end + + if traitormod.peoplePercentages[client.SteamID] == nil then + traitormod.peoplePercentages[client.SteamID] = {} + traitormod.peoplePercentages[client.SteamID].penalty = 1 + traitormod.peoplePercentages[client.SteamID].p = config.firstJoinPercentage + end + + traitormod.peoplePercentages[client.SteamID].p = amount +end + +traitormod.addPenalty = function (client, amount) + if client == nil then return end + + if traitormod.peoplePercentages[client.SteamID] == nil then + traitormod.peoplePercentages[client.SteamID] = {} + traitormod.peoplePercentages[client.SteamID].penalty = 1 + traitormod.peoplePercentages[client.SteamID].p = config.firstJoinPercentage + end + + traitormod.peoplePercentages[client.SteamID].penalty = traitormod.peoplePercentages[client.SteamID].penalty + amount +end + +traitormod.getPenalty = function (client) + if client == nil then return end + + if traitormod.peoplePercentages[client.SteamID] == nil then + traitormod.peoplePercentages[client.SteamID] = {} + traitormod.peoplePercentages[client.SteamID].penalty = 1 + traitormod.peoplePercentages[client.SteamID].p = config.firstJoinPercentage + end + + return traitormod.peoplePercentages[client.SteamID].penalty +end + +traitormod.addPercentage = function(client, amount) + if client == nil then return end + + if traitormod.peoplePercentages[client.SteamID] == nil then + traitormod.peoplePercentages[client.SteamID] = {} + traitormod.peoplePercentages[client.SteamID].penalty = 1 + traitormod.peoplePercentages[client.SteamID].p = config.firstJoinPercentage + end + + traitormod.peoplePercentages[client.SteamID].p = traitormod.peoplePercentages[client.SteamID].p + amount +end + +traitormod.getPercentage = function (client) + if client == nil then return end + + if traitormod.peoplePercentages[client.SteamID] == nil then + traitormod.peoplePercentages[client.SteamID] = {} + traitormod.peoplePercentages[client.SteamID].penalty = 1 + traitormod.peoplePercentages[client.SteamID].p = config.firstJoinPercentage + end + + return traitormod.peoplePercentages[client.SteamID].p +end + +traitormod.chooseCodes = function() + local codewords = dofile("lua/traitormod/traitorconfig.lua").codewords -- copy + + local amount = config.amountCodewords + + for i = 1, amount, 1 do + local rand = Random.Range(1, #codewords + 1) + table.insert(traitormod.selectedCodeResponses, codewords[rand]) + table.remove(codewords, rand) + end + + for i = 1, amount, 1 do + local rand = Random.Range(1, #codewords + 1) + table.insert(traitormod.selectedCodePhrases, codewords[rand]) + table.remove(codewords, rand) + end + +end + +traitormod.selectPlayerPercentages = function(ignore) + local players = util.GetValidPlayersNoBotsAndNoTraitors( + traitormod.roundtraitors) + + for i = 1, #players, 1 do + for key, value in pairs(ignore) do + if players[i] == value then + table.remove(players, i) + end + end + end + + local total = 0 + + for key, value in pairs(players) do + local client = util.clientChar(value) + + total = total + traitormod.getPercentage(client) + end + + local rng = Random.Range(0, total) + + local addup = 0 + + for key, value in pairs(players) do + local client = util.clientChar(value) + + local percentage = traitormod.getPercentage(client) + + if rng >= addup and rng <= addup + percentage then return value end + + addup = addup + percentage + + end + + return nil + +end + +traitormod.chooseTraitors = function(amount) + local traitors = {} + + for i = 1, amount, 1 do + local found = traitormod.selectPlayerPercentages(traitors) + + if found == nil then + print("Not enough players") + break + else + table.insert(traitors, found) + end + end + + return traitors +end + +traitormod.sendTraitorMessage = function(msg, client, notchatbox) + if client == nil then return end + + if notchatbox == true then + Game.SendDirectChatMessage("", msg, nil, 11, client) + else + Game.SendDirectChatMessage("", msg, nil, 7, client) + end + + Game.SendDirectChatMessage("", msg, nil, 1, client) +end + +traitormod.assignNormalTraitors = function(amount) + local traitors = traitormod.chooseTraitors(amount) + + for key, value in pairs(traitors) do traitormod.roundtraitors[value] = {} end + + local targets = util.GetValidPlayersNoTraitors(traitormod.roundtraitors) + + for key, value in pairs(traitors) do + traitormod.roundtraitors[value].objectiveType = "kill" + traitormod.roundtraitors[value].objectiveTarget = + targets[Random.Range(1, #targets + 1)] + + local mess = + "You are a traitor! Your secret mission is to assassinate " .. + traitormod.roundtraitors[value].objectiveTarget.name .. + "! Avoid being loud, make the death look like an accident. We will provide you more information after you finish your current mission." + + if util.TableCount(traitormod.roundtraitors) > 1 then + mess = mess .. + "\n\nIt is possible that there are other agents on this submarine. You dont know their names, but you do have a method of communication. Use the code words to greet the agent and code response to respond. Disguise such words in a normal-looking phrase so the crew doesn't suspect anything." + mess = mess .. "\n\n The code words are: " + + for key, va in pairs(traitormod.selectedCodePhrases) do + mess = mess .. "\"" .. va .. "\" " + end + + mess = mess .. "\n The code response is: " + + for key, va in pairs(traitormod.selectedCodeResponses) do + mess = mess .. "\"" .. va .. "\" " + end + end + + Game.Log(value.name .. + " Was assigned to be traitor, his first mission is to kill " .. + traitormod.roundtraitors[value].objectiveTarget.name, 6) + + traitormod.sendTraitorMessage(mess, util.clientChar(value)) + + end +end + +traitormod.chooseNextObjective = function(key, value) + local players = util.GetValidPlayersNoTraitors(traitormod.roundtraitors) + + if #players == 0 then + traitormod.sendTraitorMessage("Good job agent, You did it.", + util.clientChar(key), true) + + value.needNewObjective = false + + return + end + + local assassinate = players[Random.Range(1, #players + 1)] + + traitormod.sendTraitorMessage("Your next mission is to assassinate " .. + assassinate.name, util.clientChar(key), + true) + + Game.Log(key.name .. + " Was assigned another traitor mission, His mission is to kill " .. + assassinate.name, 6) + + value.objectiveTarget = assassinate + value.objectiveType = "kill" + value.needNewObjective = false +end + +Hook.Add("roundStart", "traitor_start", function() + if not traitormod.enabled then return end + + local players = util.GetValidPlayersNoBots() + + for key, value in pairs(players) do + local client = util.clientChar(value) + + if traitormod.getPenalty(client) > 1 then + traitormod.addPenalty(client, -1) + end + + traitormod.addPercentage(client, config.roundEndPercentageIncrease / traitormod.getPenalty(client)) + end + + traitormod.chooseCodes() + + local rng = Random.Range(0, 100) + + if rng < config.traitorShipChance and traitormod.traitorShipEnabled == true then + local amount = config.getAmountShipTraitors(#util.GetValidPlayers()) + + Game.Log("Infiltraiton Gamemode selected, Random = " .. rng, 6) + traitormod.roundGamemode = "Infiltraiton" + + traitormod.traitorShipRoundStart(amount) + else + traitorsAssigned = false + traitorAssignDelay = Timer.GetTime() + config.traitorSpawnDelay + + Game.Log("Assasination Gamemode was selected, Random = " .. rng, 6) + traitormod.roundGamemode = "Assasination" + + traitormod.spawnTraitorShipAndHide() + end + + for key, value in pairs(Player.GetAllClients()) do + Game.SendTraitorMessage(value, 'traitor', 'traitor', TraitorMessageType.Objective) -- enable everyone to sabotage + end + + Game.SendMessage( + "We are using Custom Traitors Plugin by EvilFactory (https://steamcommunity.com/id/evilfactory/)\n Join discord.gg/f9zvNNuxu9", + 3) +end) + +Hook.Add("roundEnd", "traitor_end", function() + if not traitormod.enabled then return end + + local msg = "Traitors of the round: " + + for key, value in pairs(traitormod.roundtraitors) do + msg = msg .. "\"" .. key.name .. "\" " + end + + msg = msg .. "\n\nGamemode: " .. traitormod.roundGamemode + + Game.SendMessage(msg, 1) + + for key, value in pairs(traitormod.roundtraitors) do + local c = util.clientChar(key) + traitormod.setPercentage(c, config.traitorPercentageSet) + traitormod.addPenalty(c, config.traitorPenalty) + end + + traitormod.roundtraitors = {} + traitormod.selectedCodeResponses = {} + traitormod.selectedCodePhrases = {} + warningClients = {} +end) + +Hook.Add("think", "traitor_think", function() + if not traitormod.enabled then return end + + if not traitorsAssigned and traitorAssignDelay < Timer.GetTime() then + local amount = config.getAmountTraitors(#util.GetValidPlayers()) + traitormod.assignNormalTraitors(amount) + + traitorsAssigned = true + end + + for key, value in pairs(Player.GetAllCharacters()) do + + if warningClients[value] == nil then + + if value.IsDead == true then + local attackers = value.LastAttacker + -- and attackers ~= value + if util.characterIsTraitor(attackers, traitormod.roundtraitors) and + attackers ~= value then + traitormod.sendTraitorMessage( + "Your death was caused by a traitor on a secret mission.", + util.clientChar(value), true) + end + + warningClients[value] = true + end + + end + end + + for key, value in pairs(traitormod.roundtraitors) do + if key ~= nil and key.IsDead == false then + + if value.needNewObjective == true and Timer.GetTime() > + value.objectiveTimer then + traitormod.chooseNextObjective(key, value) + end + + if value.objectiveTarget ~= nil then + + if value.objectiveTarget.IsDead then + traitormod.sendTraitorMessage( + "Great job, You killed " .. value.objectiveTarget.name .. + ". We will provide you your next mission shortly.", + util.clientChar(key), true) + + value.objectiveTarget = nil + + value.needNewObjective = true + value.objectiveTimer = + Timer.GetTime() + config.nextMissionDelay + + end + + end + + end + end + +end) + +Hook.Add("chatMessage", "chatcommands", function(msg, client) + + if bit32.band(client.Permissions, 0x40) == 0x40 then + if msg == "!toggletraitormod" then + traitormod.enabled = not traitormod.enabled + + if traitormod.enabled then + Game.SendDirectChatMessage("", "TraitorMod Enabled", nil, 1, + client) + else + Game.SendDirectChatMessage("", "TraitorMod Disabled", nil, 1, + client) + end + + Game.OverrideTraitors(traitormod.enabled) + + return true + end + + if msg == "!toggletraitorship" then + traitormod.traitorShipEnabled = not traitormod.traitorShipEnabled + + if traitormod.traitorShipEnabled then + Game.SendDirectChatMessage("", "Traitor Ship Enabled", nil, 1, + client) + else + Game.SendDirectChatMessage("", "Traitor Ship Disabled", nil, 1, + client) + end + + return true + end + + if msg == "!traitors" then + local tosend = "Traitors of the round: " + + for key, value in pairs(traitormod.roundtraitors) do + tosend = tosend .. "\"" .. key.name .. "\" " + end + + traitormod.sendTraitorMessage(tosend, client) + + return true + end + + if msg == "!traitoralive" then + local num = 0 + + for key, value in pairs(traitormod.roundtraitors) do + if key.IsDead == false then + num = num + 1 + end + end + + if num > 0 then + traitormod.sendTraitorMessage("There are traitors alive.", client) + else + traitormod.sendTraitorMessage("All traitors are dead!", client) + end + + + return true + end + + if msg == "!percentages" then + local msg = "" + for key, value in pairs(Player.GetAllClients()) do + + msg = msg .. value.name .. " - " .. + math.floor(traitormod.getPercentage(value)) .. "%\n" + end + + traitormod.sendTraitorMessage(msg, client) + + return true + end + end + + if msg == "!percentage" then + + traitormod.sendTraitorMessage("You have " .. + math.floor(traitormod.getPercentage(client)) .. + "% of being traitor", client) + + return true + end + + if util.stringstarts(msg, "!traitor") then + if util.characterIsTraitor(client.Character, traitormod.roundtraitors) then + local msg = "You are a traitor. " + + if traitormod.roundtraitors[client.Character].objectiveTarget ~= nil then + msg = msg .. "\nCurrent Mission: kill " .. + traitormod.roundtraitors[client.Character] + .objectiveTarget.name + end + + if util.TableCount(traitormod.roundtraitors) > 1 then + + msg = msg .. "\n\n The code words are: " + + for key, va in pairs(traitormod.selectedCodePhrases) do + msg = msg .. "\"" .. va .. "\" " + end + + msg = msg .. "\n The code response is: " + + for key, va in pairs(traitormod.selectedCodeResponses) do + msg = msg .. "\"" .. va .. "\" " + end + + end + + traitormod.sendTraitorMessage(msg, client) + else + traitormod.sendTraitorMessage("You are not a traitor.", client) + end + + return true + end +end) + +Traitormod = traitormod + diff --git a/Example/Lua/traitormod/autorun/traitorship.lua b/Example/Lua/traitormod/autorun/traitorship.lua new file mode 100644 index 000000000..50bc493de --- /dev/null +++ b/Example/Lua/traitormod/autorun/traitorship.lua @@ -0,0 +1,129 @@ +local traitormod = Traitormod +local respawnshuttle = nil +local loadedpeople = {} + +local config = dofile("lua/traitormod/traitorconfig.lua") +local util = dofile("lua/traitormod/util.lua") + +Game.OverrideRespawnSub(true) + +Hook.Add("think", "traitorShip", function() + if respawnshuttle ~= nil then + + local pos1 = Submarine.MainSub.WorldPosition + local pos2 = respawnshuttle.WorldPosition + + if Vector2.Distance(pos1, pos2) < config.traitorShipGodModeDistance then + respawnshuttle.GodMode = false + end + + for key, value in pairs(traitormod.roundtraitors) do + local client = util.clientChar(key) + + if client ~= nil then + if client.InGame == true and loadedpeople[key] == nil then + loadedpeople[key] = {} + loadedpeople[key].next = Timer.GetTime() + 15 + elseif loadedpeople[key] ~= nil and Timer.GetTime() < + loadedpeople[key].next then + Player.SetClientCharacter(client, key) + end + + end + end + + end +end) + +Hook.Add("roundEnd", "traitorShipRemove", function() + respawnshuttle = nil + + loadedpeople = {} +end) + +traitormod.spawnTraitorShipAndHide = function() + Game.SetRespawnSubTeam(2) + Game.DispatchRespawnSub() + + local sub = Game.GetRespawnSub() + sub.ShowSonarMarker = false + + sub.GodMode = true + + local steering = Game.GetSubmarineSteering(sub) + steering.AutoPilot = false + + sub.SetPosition({0, Level.Loaded.BottomPos + 1000}) + + return sub +end + +traitormod.spawnTraitorShip = function() + Game.SetRespawnSubTeam(2) + Game.DispatchRespawnSub() + + local sub = Game.GetRespawnSub() + respawnshuttle = sub + + sub.ShowSonarMarker = false + + local positions = Level.Loaded.PositionsOfInterest + + local goodpositions = {} + + for key, value in ipairs(positions) do + if value.PositionType == PositionType.MainPath then + table.insert(goodpositions, value) + end + end + + -- sub.SetPosition({Level.Loaded.EndPosition[1], Level.Loaded.EndPosition[2] - 10000}) + sub.SetPosition(goodpositions[math.floor(#goodpositions / 2)].Position + .ToVector2()) + + sub.GodMode = true + + local steering = Game.GetSubmarineSteering(sub) + + steering.AutoPilot = false + + return sub +end + +traitormod.traitorShipRoundStart = function(maxplayers) + local sub = traitormod.spawnTraitorShip() + + local assignedNowTraitors = traitormod.chooseTraitors(maxplayers) + + for index, value in pairs(assignedNowTraitors) do + traitormod.roundtraitors[value] = {} + + local mess = + "You are a traitor! Your mission is to exterminate the Main Sub's Crew, cooperate with your fellow agents." + + mess = mess .. + "\n\nUse the codewords to communicate with the other agents." + mess = mess .. "\n\n The code words are: " + + for key, va in pairs(traitormod.selectedCodePhrases) do + mess = mess .. "\"" .. va .. "\" " + end + + mess = mess .. "\n The code response is: " + + for key, va in pairs(traitormod.selectedCodeResponses) do + mess = mess .. "\"" .. va .. "\" " + end + + Game.Log(value.name .. " Was assigned to be Ship traitor", 6) + + local cl = util.clientChar(value) + + traitormod.sendTraitorMessage(mess, cl) + + local waypoint = WayPoint.GetRandom(SpawnType.Human, nil, sub) + + value.TeleportTo(waypoint.WorldPosition) + -- Player.SetClientCharacter(cl, value) + end +end diff --git a/Example/Lua/traitormod/traitorconfig.lua b/Example/Lua/traitormod/traitorconfig.lua new file mode 100644 index 000000000..e132c3c19 --- /dev/null +++ b/Example/Lua/traitormod/traitorconfig.lua @@ -0,0 +1,36 @@ +local config = {} + +local codewords = { + "pomegrenade", "tabacco", "fish", "nonsense", "europa", "clown", + "thalamus", "hungry", "renegade", "angry", "green", "flamingos", "sink", + "mask", "boomer", "sweet", "ice", "charybdis", "cult", "secret", "moloch", + "husk", "rusted", "ruins", "red", "boat", "cats", "rats", "jeepers", "bench", + "tire", "trunk", "blow sticks", "thrashers" +} + +config.codewords = codewords +config.amountCodewords = 2 +config.traitorSpawnDelay = 60 +config.nextMissionDelay = 60 +config.traitorShipChance = 15 +config.traitorShipGodModeDistance = 4000 + +-- Traitor Selection Options +config.roundEndPercentageIncrease = 10 +config.firstJoinPercentage = 10 +config.traitorPercentageSet = 5 +config.traitorPenalty = 5 + +-- >=12 players = 3 traitors, >=8 players = 2 traitors, default = 1 traitor +config.getAmountTraitors = function (amountClients) + if amountClients >= 12 then return 3 end + + if amountClients >= 8 then return 2 end + + return 1 +end + +-- shipTraitors and normal traitors will be selected equally +config.getAmountShipTraitors = config.getAmountTraitors + +return config; \ No newline at end of file diff --git a/Example/Lua/traitormod/util.lua b/Example/Lua/traitormod/util.lua new file mode 100644 index 000000000..eba665708 --- /dev/null +++ b/Example/Lua/traitormod/util.lua @@ -0,0 +1,116 @@ +local util = {} + +util.clientChar = function(char) + local clients = Player.GetAllClients() + + for key, client in pairs(clients) do + if (client.Character == char) then return client end + end + + return nil +end + +util.GetDeadClients = function() + local valid = {} + + for key, value in pairs(Player.GetAllClients()) do + if value.InGame then + if value.Character == nil then table.insert(valid, value) end + + if value.Character ~= nil and value.Character.IsDead == true then + table.insert(valid, value) + end + + end + end + + return valid +end + +util.GetValidPlayers = function() + local chars = Player.GetAllCharacters() + local valid = {} + + for key, value in pairs(chars) do + if (value.IsHuman == true and value.IsDead == false) and + value.ClientDisconnected == false then + table.insert(valid, value) + end + end + + return valid + +end + +function util.stringstarts(String, Start) + return string.sub(String, 1, string.len(Start)) == Start +end + +util.characterIsTraitor = function(char, traitors) + + for key, value in pairs(traitors) do + if char == key then return true end + end + + return false +end + +util.GetValidPlayersNoBotsAndNoTraitors = function(traitors) + local chars = Player.GetAllCharacters() + local valid = {} + + for key, value in pairs(chars) do + if (value.IsHuman == true and value.IsDead == false) and + value.ClientDisconnected == false then + if value.IsBot == false and traitors[value] == nil then table.insert(valid, value) end + end + end + + return valid + +end + +util.GetValidPlayersNoBots = function() + local chars = Player.GetAllCharacters() + local valid = {} + + for key, value in pairs(chars) do + if (value.IsHuman == true and value.IsDead == false) and + value.ClientDisconnected == false then + if value.IsBot == false then table.insert(valid, value) end + end + end + + return valid + +end + +util.TableCount = function (tbl) + local count = 0 + + for key, value in pairs(tbl) do + count = count + 1 + end + + return count +end + +util.GetValidPlayersNoTraitors = function(traitors) + local chars = Player.GetAllCharacters() + local valid = {} + + for key, value in pairs(chars) do + if (value.IsHuman == true and value.IsDead == false) and + value.ClientDisconnected == false then + if traitors[value] == nil then + table.insert(valid, value) + end + end + end + + return valid + +end + + +return util \ No newline at end of file