571 lines
18 KiB
Lua
571 lines
18 KiB
Lua
local traitormod = {}
|
|
traitormod.peoplePercentages = {}
|
|
|
|
traitormod.roundtraitors = {}
|
|
traitormod.selectedCodeResponses = {}
|
|
traitormod.selectedCodePhrases = {}
|
|
traitormod.gamemodes = {}
|
|
|
|
traitormod.disableRadioChat = false
|
|
|
|
local endingRound = false
|
|
local roundEndDelay = 0
|
|
|
|
local traitorAssignDelay = 0
|
|
local traitorsAssigned = true
|
|
local traitorsRoundStartAssigned = false
|
|
local warningClients = {}
|
|
|
|
local config = dofile("lua/traitormod/traitorconfig.lua")
|
|
local util = dofile("lua/traitormod/util.lua")
|
|
|
|
Game.OverrideTraitors(config.enableTraitors) -- shutup old traitors
|
|
Game.AllowWifiChat(config.enableWifiChat) -- deprecated
|
|
|
|
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 0 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 0 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
|
|
|
|
mess = mess .. "\n(You can type in local chat !traitor, to check this information again.)"
|
|
|
|
|
|
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()
|
|
|
|
Game.SendMessage(
|
|
"We are using Custom Traitors Plugin by EvilFactory (https://steamcommunity.com/id/evilfactory/)\n Join discord.gg/f9zvNNuxu9",
|
|
3)
|
|
|
|
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()
|
|
|
|
if config.enableTraitors then
|
|
|
|
local rng = Random.Range(0, 100)
|
|
|
|
if (rng < config.traitorShipChance and config.traitorShipEnabled == true) and Game.GetRespawnSub() ~= nil then
|
|
local amount = config.getAmountShipTraitors(#util.GetValidPlayers())
|
|
|
|
Game.Log("Infiltraition Gamemode selected, Random = " .. rng, 6)
|
|
table.insert(traitormod.gamemodes, "Infiltraition")
|
|
|
|
traitormod.traitorShipRoundStart(amount)
|
|
else
|
|
traitorsAssigned = false
|
|
traitorAssignDelay = Timer.GetTime() + config.traitorSpawnDelay
|
|
|
|
Game.Log("Assasination Gamemode was selected, Random = " .. rng, 6)
|
|
table.insert(traitormod.gamemodes, "Assasination")
|
|
|
|
if config.traitorShipEnabled then
|
|
if Game.GetRespawnSub() == nil then
|
|
Game.SendMessage("TraitorMod Warning: Traitor Ship enabled but respawn shuttle disabled!", 1)
|
|
else
|
|
traitormod.spawnTraitorShipAndHide()
|
|
end
|
|
end
|
|
end
|
|
|
|
if config.enableCommunicationsOffline then
|
|
rng = Random.Range(0, 100)
|
|
|
|
if rng < config.communicationsOfflineChance then
|
|
table.insert(traitormod.gamemodes, "Offline Communications")
|
|
traitormod.disableRadioChat = true
|
|
|
|
Game.SendMessage(
|
|
"—-radiation closing in on our location, comms down!", 11)
|
|
|
|
Game.SendMessage(
|
|
"—-radiation closing in on our location, comms down!", 3)
|
|
|
|
for key, value in pairs(Player.GetAllCharacters()) do
|
|
if value.IsHuman then
|
|
Player.SetRadioRange(value, 0)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
if config.enableSabotage then
|
|
for key, value in pairs(Player.GetAllClients()) do
|
|
|
|
if value.Character then
|
|
value.Character.IsTraitor = true
|
|
end
|
|
|
|
Game.SendTraitorMessage(value, 'traitor', 'traitor',
|
|
TraitorMessageType.Objective) -- enable everyone to sabotage
|
|
end
|
|
end
|
|
|
|
end)
|
|
|
|
Hook.Add("roundEnd", "traitor_end", function()
|
|
if config.enableTraitors then
|
|
|
|
local msg = "Traitors of the round: "
|
|
|
|
for key, value in pairs(traitormod.roundtraitors) do
|
|
msg = msg .. "\"" .. key.name .. "\" "
|
|
end
|
|
|
|
msg = msg .. "\n\nGamemodes:"
|
|
|
|
for key, value in pairs(traitormod.gamemodes) do
|
|
msg = msg .. " \"" .. value .. "\""
|
|
end
|
|
|
|
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
|
|
|
|
end
|
|
|
|
traitorsRoundStartAssigned = false
|
|
endingRound = false
|
|
traitormod.roundtraitors = {}
|
|
traitormod.selectedCodeResponses = {}
|
|
traitormod.selectedCodePhrases = {}
|
|
traitormod.gamemodes = {}
|
|
warningClients = {}
|
|
end)
|
|
|
|
Hook.Add("think", "traitor_think", function()
|
|
if not traitorsAssigned and traitorAssignDelay < Timer.GetTime() then
|
|
local amount = config.getAmountTraitors(#util.GetValidPlayers())
|
|
traitormod.assignNormalTraitors(amount)
|
|
|
|
traitorsAssigned = true
|
|
traitorsRoundStartAssigned = true
|
|
end
|
|
|
|
if endingRound == true and roundEndDelay < Timer.GetTime() then
|
|
Game.ExecuteCommand('endgame')
|
|
|
|
endingRound = false
|
|
end
|
|
|
|
if traitorsRoundStartAssigned and config.endRoundWhenAllTraitorsDie 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
|
|
Game.SendMessage('All traitors died! Ending round in ' .. config.endRoundDelayInSeconds .. ' seconds.', 1)
|
|
|
|
endingRound = true
|
|
roundEndDelay = Timer.GetTime() + config.endRoundDelayInSeconds
|
|
traitorsRoundStartAssigned = false
|
|
end
|
|
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 == "!toggletraitorship" then
|
|
config.traitorShipEnabled = not config.traitorShipEnabled
|
|
|
|
if config.traitorShipEnabled then
|
|
Game.SendDirectChatMessage("", "Traitor Ship Enabled", nil, 1,
|
|
client)
|
|
else
|
|
Game.SendDirectChatMessage("", "Traitor Ship Disabled", nil, 1,
|
|
client)
|
|
end
|
|
|
|
Game.OverrideRespawnSub(config.traitorShipEnabled)
|
|
|
|
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 msg == "!help" then
|
|
|
|
|
|
traitormod.sendTraitorMessage("\nCommands\n!help\n!traitor\n!traitors\n!percentage\n!percentages\n!toggletraitorship", 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
|
|
|