C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust;
namespace Oxide.Plugins
{
[Info("Event Manager", "Reneb / k1lly0u", "2.0.24", ResourceId = 740)]
class EventManager : RustPlugin
{
#region Fields
[PluginReference]
Plugin Spawns;
[PluginReference]
Plugin Kits;
[PluginReference]
Plugin ZoneManager;
[PluginReference]
Plugin ServerRewards;
[PluginReference]
Plugin Economics;
private string EventSpawnFile;
private string EventGameName;
private string ZoneName;
private string TokenType;
private bool EventOpen;
private bool EventStarted;
private bool EventEnded;
private bool EventPending;
private int EventMaxPlayers = 0;
private int EventMinPlayers = 0;
private int EventAutoNum = -1;
public int PlayTimer;
public float LastAnnounce;
public bool AutoEventLaunched = false;
public bool UseClassSelection;
public GameMode EventMode;
private List<string> EventGames;
private List<EventPlayer> EventPlayers;
public List<ulong> Godmode;
public List<Timer> AutoArenaTimers;
private Dictionary<ulong, Timer> KillTimers;
private ConfigData configData;
ClassData classData;
private DynamicConfigFile Class_Data;
static bool Debug = false;
#endregion
#region Classes
class EventPlayer : MonoBehaviour
{
public BasePlayer player;
public float health;
public float calories;
public float hydration;
public bool inEvent;
public bool savedInventory;
public bool savedHome;
public bool OOB;
public string currentClass;
public List<EventInvItem> InvItems = new List<EventInvItem>();
public Vector3 Home;
void Awake()
{
inEvent = true;
savedInventory = false;
savedHome = false;
player = GetComponent<BasePlayer>();
ELog($"{player.displayName} component init");
}
public void SaveHealth()
{
ELog($"{player.displayName} saving health");
health = player.health;
calories = player.metabolism.calories.value;
hydration = player.metabolism.hydration.value;
}
public void SaveHome()
{
ELog($"{player.displayName} saving home");
if (!savedHome)
Home = player.transform.position;
savedHome = true;
}
public void TeleportHome()
{
ELog($"{player.displayName} TP home");
if (!savedHome)
return;
TPPlayer(player, Home);
savedHome = false;
}
public void SaveInventory()
{
ELog($"{player.displayName} saving inv");
if (savedInventory)
return;
InvItems.Clear();
InvItems.AddRange(GetItems(player.inventory.containerWear, "wear"));
InvItems.AddRange(GetItems(player.inventory.containerMain, "main"));
InvItems.AddRange(GetItems(player.inventory.containerBelt, "belt"));
ELog($"{player.displayName} inventory count: {InvItems.Count}");
savedInventory = true;
}
private IEnumerable<EventInvItem> GetItems(ItemContainer container, string containerName)
{
return container.itemList.Select(item => new EventInvItem
{
itemid = item.info.itemid,
container = containerName,
amount = item.amount,
ammo = (item.GetHeldEntity() as BaseProjectile)?.primaryMagazine.contents ?? 0,
skin = item.skin,
condition = item.condition,
contents = item.contents?.itemList.Select(item1 => new EventInvItem
{
itemid = item1.info.itemid,
amount = item1.amount,
condition = item1.condition
}).ToArray()
});
}
public void RestoreInventory()
{
ELog($"{player.displayName} restoring inventory, saved count: {InvItems.Count}");
player.inventory.Strip();
foreach (var kitem in InvItems)
{
var item = ItemManager.CreateByItemID(kitem.itemid, kitem.amount, kitem.skin);
item.condition = kitem.condition;
var weapon = item.GetHeldEntity() as BaseProjectile;
if (weapon != null) weapon.primaryMagazine.contents = kitem.ammo;
player.inventory.GiveItem(item, kitem.container == "belt" ? player.inventory.containerBelt : kitem.container == "wear" ? player.inventory.containerWear : player.inventory.containerMain);
if (kitem.contents == null) continue;
foreach (var ckitem in kitem.contents)
{
var item1 = ItemManager.CreateByItemID(ckitem.itemid, ckitem.amount);
if (item1 == null) continue;
item1.condition = ckitem.condition;
item1.MoveToContainer(item.contents);
}
}
ELog($"{player.displayName} restored count: {player.inventory.containerBelt.itemList.Count + player.inventory.containerMain.itemList.Count + player.inventory.containerWear.itemList.Count}");
savedInventory = false;
}
}
class EventInvItem
{
public int itemid;
public bool bp;
public int skin;
public string container;
public int amount;
public float condition;
public int ammo;
public EventInvItem[] contents;
}
class ConfigData
{
public string Default_Gamemode { get; set; }
public string Default_Spawnfile { get; set; }
public int Battlefield_Timer { get; set; }
public bool KillDeserters { get; set; }
public int Required_AuthLevel { get; set; }
public string Messaging_MainColor { get; set; }
public string Messaging_MsgColor { get; set; }
public bool Announce_Event { get; set; }
public bool AnnounceDuring_Event { get; set; }
public int AnnounceEvent_Interval { get; set; }
public bool UseEconomicsAsTokens { get; set; }
public bool UseClassSelector_Default { get; set; }
public AutoEvents z_AutoEvents { get; set; }
}
class AutoEvents
{
public int GameInterval { get; set; }
public bool AutoCancel { get; set; }
public int AutoCancel_Timer { get; set; }
public List<AutoEventSetup> z_AutoEventSetup { get; set; }
}
class AutoEventSetup
{
public bool UseClassSelector { get; set; }
public string GameType { get; set; }
public GameMode EventMode { get; set; }
public string Spawnfile { get; set; }
public string Kit { get; set; }
public bool CloseOnStart { get; set; }
public int TimeToJoin { get; set; }
public int MinimumPlayers { get; set; }
public int MaximumPlayers { get; set; }
public int TimeLimit { get; set; }
public string ZoneID { get; set; }
}
class ClassData
{
public Dictionary<string, string> ClassKits = new Dictionary<string, string>();
}
public class UI
{
static public CuiElementContainer CreateElementContainer(string panelName, string color, string aMin, string aMax, bool useCursor)
{
var NewElement = new CuiElementContainer()
{
{
new CuiPanel
{
Image = {Color = color},
RectTransform = {AnchorMin = aMin, AnchorMax = aMax},
CursorEnabled = useCursor
},
new CuiElement().Parent = "Overlay",
panelName
}
};
return NewElement;
}
static public void CreatePanel(ref CuiElementContainer container, string panel, string color, string aMin, string aMax, bool cursor = false)
{
container.Add(new CuiPanel
{
Image = { Color = color },
RectTransform = { AnchorMin = aMin, AnchorMax = aMax },
CursorEnabled = cursor
},
panel);
}
static public void CreateLabel(ref CuiElementContainer container, string panel, string color, string text, int size, string aMin, string aMax, TextAnchor align = TextAnchor.MiddleCenter)
{
container.Add(new CuiLabel
{
Text = { Color = color, FontSize = size, Align = align, Text = text },
RectTransform = { AnchorMin = aMin, AnchorMax = aMax }
},
panel);
}
static public void CreateButton(ref CuiElementContainer container, string panel, string color, string text, int size, string aMin, string aMax, string command, TextAnchor align = TextAnchor.MiddleCenter)
{
container.Add(new CuiButton
{
Button = { Color = color, Command = command, FadeIn = 1.0f },
RectTransform = { AnchorMin = aMin, AnchorMax = aMax },
Text = { Text = text, FontSize = size, Align = align }
},
panel);
}
}
public enum GameMode
{
Normal,
Battlefield
}
#endregion
#region Oxide Hooks
void Loaded()
{
EventGames = new List<string>();
EventMode = GameMode.Normal;
EventPlayers = new List<EventPlayer>();
AutoArenaTimers = new List<Timer>();
KillTimers = new Dictionary<ulong, Timer>();
Class_Data = Interface.Oxide.DataFileSystem.GetFile("EventManager_Classes");
}
void OnServerInitialized()
{
lang.RegisterMessages(Messages, this);
LoadVariables();
LoadData();
EventOpen = false;
EventStarted = false;
EventEnded = true;
EventPending = false;
UseClassSelection = configData.UseClassSelector_Default;
EventGameName = configData.Default_Gamemode;
timer.Once(0.2f, InitializeGames);
}
void InitializeGames()
{
//Interface.Oxide.CallHook("RegisterGame");
SelectSpawnfile(configData.Default_Spawnfile);
}
void Unload()
{
foreach (var player in BasePlayer.activePlayerList) DestroyUI(player);
EndEvent();
DestroyGame();
}
void OnPlayerRespawned(BasePlayer player)
{
if (!EventStarted) return;
if (!player.GetComponent<EventPlayer>()) return;
if (player.GetComponent<EventPlayer>().inEvent)
{
if (!EventStarted) return;
TeleportPlayerToEvent(player);
}
else
{
RedeemInventory(player);
TeleportPlayerHome(player);
TryErasePlayer(player);
}
}
void OnPlayerAttack(BasePlayer player, HitInfo hitinfo)
{
if (!EventStarted) return;
if (player.GetComponent<EventPlayer>() == null || !(player.GetComponent<EventPlayer>().inEvent))
return;
if (hitinfo.HitEntity != null)
Interface.Oxide.CallHook("OnEventPlayerAttack", player, hitinfo);
return;
}
void OnEntityDeath(BaseEntity entity, HitInfo hitinfo)
{
if (!EventStarted) return;
if ((entity as BasePlayer)?.GetComponent<EventPlayer>() == null) return;
Interface.Oxide.CallHook("OnEventPlayerDeath", ((BasePlayer)entity), hitinfo);
return;
}
void OnPlayerDisconnected(BasePlayer player)
{
if (!EventStarted) return;
if (player.GetComponent<EventPlayer>() != null)
LeaveEvent(player);
}
void OnEntityTakeDamage(BaseEntity entity, HitInfo info)
{
if (!EventStarted) return;
var player = entity as BasePlayer;
if (Godmode == null || player == null) return;
if (Godmode.Contains(player.userID))
{
info.damageTypes = new DamageTypeList();
info.HitMaterial = 0;
info.PointStart = Vector3.zero;
}
}
#endregion
#region Checks
bool hasEventStarted()
{
return EventStarted;
}
bool isPlaying(BasePlayer player)
{
EventPlayer eplayer = player.GetComponent<EventPlayer>();
return eplayer != null && eplayer.inEvent;
}
object canRedeemKit(BasePlayer player)
{
if (!EventStarted) return null;
TryErasePlayer(player);
EventPlayer eplayer = player.GetComponent<EventPlayer>();
if (eplayer == null) return null;
return false;
}
object canShop(BasePlayer player)
{
if (!EventStarted) return null;
EventPlayer eplayer = player.GetComponent<EventPlayer>();
if (eplayer == null) return null;
return GetMessage("CanShop");
}
object CanTeleport(BasePlayer player)
{
if (!EventStarted) return null;
EventPlayer eplayer = player.GetComponent<EventPlayer>();
if (eplayer == null) return null;
return GetMessage("CanTP");
}
#endregion
#region Config
private void LoadVariables()
{
LoadConfigVariables();
SaveConfig();
}
private void LoadConfigVariables()
{
configData = Config.ReadObject<ConfigData>();
}
protected override void LoadDefaultConfig()
{
Puts("Creating a new config file");
var config = new ConfigData
{
AnnounceDuring_Event = true,
AnnounceEvent_Interval = 120,
Announce_Event = true,
Battlefield_Timer = 1200,
Default_Gamemode = "Deathmatch",
Default_Spawnfile = "deathmatchspawns",
KillDeserters = true,
Required_AuthLevel = 1,
Messaging_MainColor = "#FF8C00",
Messaging_MsgColor = "#939393",
UseEconomicsAsTokens = false,
UseClassSelector_Default = true,
z_AutoEvents = new AutoEvents
{
AutoCancel = true,
AutoCancel_Timer = 300,
GameInterval = 1200,
z_AutoEventSetup = CreateDefaultAutoConfig()
}
};
SaveConfig(config);
}
void SaveConfig(ConfigData config)
{
Config.WriteObject(config, true);
}
static List<AutoEventSetup> CreateDefaultAutoConfig()
{
var newautoconfiglist = new List<AutoEventSetup>
{
new AutoEventSetup
{
GameType = "Deathmatch",
EventMode = GameMode.Battlefield,
Spawnfile = "deathmatchspawns",
Kit = "",
CloseOnStart = true,
TimeToJoin = 60,
TimeLimit = 1800,
MinimumPlayers = 2,
MaximumPlayers = 20,
UseClassSelector = false,
ZoneID = null
},
new AutoEventSetup
{
GameType = "TeamDeathmatch",
EventMode = GameMode.Normal,
Spawnfile = "tdm_spawns_a",
Kit = "tdmkit",
CloseOnStart = false,
TimeToJoin = 60,
TimeLimit = 0,
MinimumPlayers = 2,
MaximumPlayers = 20,
UseClassSelector = false,
ZoneID = null
},
new AutoEventSetup
{
GameType = "GunGame",
EventMode = GameMode.Battlefield,
Spawnfile = "ggspawns",
Kit = "ggkit",
CloseOnStart = false,
TimeToJoin = 60,
TimeLimit = 0,
MinimumPlayers = 2,
MaximumPlayers = 20,
UseClassSelector = false,
ZoneID = null
},
new AutoEventSetup
{
GameType = "ChopperSurvival",
EventMode = GameMode.Normal,
Spawnfile = "csspawns",
Kit = "cskit",
CloseOnStart = true,
TimeToJoin = 60,
TimeLimit = 0,
MinimumPlayers = 1,
MaximumPlayers = 20,
UseClassSelector = false,
ZoneID = null
}
};
return newautoconfiglist;
}
#endregion
#region Messaging
private void MSG(BasePlayer player, string langkey, bool title = true)
{
string message = $"<color={configData.Messaging_MsgColor}>{GetMessage(langkey)}</color>";
if (title) message = $"<color={configData.Messaging_MainColor}>{GetMessage("Title")}</color>" + message;
SendReply(player, message);
}
void BroadcastToChat(string msg)
{
ELog(msg);
PrintToChat($"<color={configData.Messaging_MainColor}>{GetMessage("Title")}</color><color={configData.Messaging_MsgColor}>{GetMessage(msg)}</color>");
}
private string GetMessage(string key) => lang.GetMessage(key, this);
[HookMethod("BroadcastEvent")]
public void BroadcastEvent(string msg)
{
foreach (EventPlayer eventplayer in EventPlayers)
SendReply(eventplayer.player, $"<color={configData.Messaging_MainColor}>" + msg + "</color>");
}
Dictionary<string, string> Messages = new Dictionary<string, string>
{
{ "multipleNames", "Multiple players found"},
{ "noPlayerFound", "No players found"},
{ "MessagesEventMinPlayers", "The Event {0} has reached min players and will start in {1} seconds"},
{ "MessagesEventMaxPlayers", "The Event {0} has reached max players.You may not join for the moment"},
{ "MessagesEventStatusClosedStarted", "The Event {0} has already started, it's too late to join."},
{ "Title", "Event Manager: "},
{ "MessagesEventStatusClosedEnd", "There is currently no event"},
{ "MessagesEventStatusOpenStarted", "The Event {0} has started, but is still opened: /event join"},
{ "MessagesEventStatusOpen", "The Event {0} is currently opened for entries: /event, join"},
{ "MessagesEventCloseAndEnd", "The Event needs to be closed and ended before using this command."},
{ "MessagesEventNotAnEvent", "This Game {0} isn't registered, did you reload the game after loading Event - Core?"},
{ "MessagesEventNotInEvent", "You are not currently in the Event."},
{ "MessagesEventBegin", "Event: {0} is about to begin!"},
{ "MessagesEventLeft", "{0} has left the Event! (Total Players: {1})"},
{ "MessagesEventJoined", "{0} has joined the Event! (Total Players: {1})"},
{ "MessagesEventAlreadyJoined", "You are already in the Event."},
{ "MessagesEventPEnd", "Event: {0} is now over, restoring players and sending them home!"},
{ "MessagesEventEnd", "All players respawned, {0} has ended!"},
{ "MessagesEventNoGamePlaying", "An Event game is not underway."},
{ "MessagesEventCancel", "The Event was cancelled!"},
{ "MessagesEventClose", "The Event entrance is now closed!"},
{ "MessagesEventOpen", "The Event is now open for : {0} ! Type /event join to join!"},
{ "MessagesPermissionsNotAllowed", "You are not allowed to use this command"},
{ "MessagesEventNotSet", "An Event game must first be chosen."},
{ "MessagesErrorSpawnfileIsNull", "The spawnfile can't be set to null"},
{ "MessagesEventNoSpawnFile", "A spawn file must first be loaded."},
{ "MessagesEventAlreadyOpened", "The Event is already open."},
{ "MessagesEventAlreadyClosed", "The Event is already closed."},
{ "MessagesEventAlreadyStarted", "An Event game has already started."},
{ "ClassSelect", "Choose your class!" },
{ "ClassNotice", "You can reopen this menu at any time by typing /event class" },
{ "CanShop", "You are not allowed to shop while in an Event" },
{ "CanTP", "You are not allowed to teleport while in an Event" },
{ "NoPlayers", "Not enough players" },
{ "NoAuto", "No Automatic Events Configured" },
{ "NoAutoInit", "No Events were successfully initialized, check that your events are correctly configured" },
{ "TimeLimit", "Time limit reached" },
{ "EventCancelled", "Event {0} was cancelled because: {1}" },
{ "EventOpen", "Event {0} in now opened, you can join it by typing /event join" },
{ "StillOpen", "Event {0} is still open, you can join it by typing /event join" },
{ "EventClosed", "The Event is currently closed." },
{ "NotInEvent", "You are not currently in the Event." },
{ "NullKitname", "You can't have a null kitname" },
{ "NoKits", "Unable to find the Kits plugin" },
{ "KitNotExist", "The kit {0} doesn't exist" },
{ "CancelAuto", "Auto events have been cancelled" }
};
#endregion
#region Class Selection
private void SelectClass(BasePlayer player)
{
string panelName = "ClassSelector";
CuiHelper.DestroyUi(player, panelName);
if (player.IsSleeping() || player.IsReceivingSnapshot() || player.IsDead())
{
timer.Once(3, () => SelectClass(player));
return;
}
var Class_Element = UI.CreateElementContainer(panelName, "0.1 0.1 0.1 0.98", "0.05 0.05", "0.95 0.95", true);
UI.CreatePanel(ref Class_Element, panelName, "0.9 0.9 0.9 0.1", "0.04 0.05", "0.96 0.94");
UI.CreateLabel(ref Class_Element, panelName, "0.9 0.9 0.9 1.0", $"<color={configData.Messaging_MainColor}>{EventGameName}</color>", 24, "0.05 0.85", "0.95 0.92");
UI.CreateLabel(ref Class_Element, panelName, "0.9 0.9 0.9 1.0", $"<color={configData.Messaging_MainColor}>{GetMessage("ClassSelect")}</color>", 24, "0.05 0.75", "0.95 0.83");
UI.CreateLabel(ref Class_Element, panelName, "0.9 0.9 0.9 1.0", $"<color={configData.Messaging_MainColor}>{GetMessage("ClassNotice")}</color>", 18, "0.05 0.05", "0.95 0.12");
int i = 0;
foreach (var entry in classData.ClassKits)
{
CreateClassButton(ref Class_Element, panelName, entry.Key, entry.Value, i);
i++;
}
CuiHelper.AddUi(player, Class_Element);
}
private void CreateClassButton(ref CuiElementContainer container, string panelName, string name, string kit, int number)
{
Vector2 dimensions = new Vector2(0.25f, 0.07f);
Vector2 origin = new Vector2(0.095f, 0.6f);
float offsetY = 0;
float offsetX = 0;
switch (number)
{
case 0:
case 1:
case 2:
offsetX = (0.03f + dimensions.x) * number;
break;
case 3:
case 4:
case 5:
{
offsetX = (0.03f + dimensions.x) * (number - 3);
offsetY = (0.07f + dimensions.y) * 1;
}
break;
case 6:
case 7:
case 8:
{
offsetX = (0.03f + dimensions.x) * (number - 6);
offsetY = (0.07f + dimensions.y) * 2;
}
break;
}
Vector2 offset = new Vector2(offsetX, -offsetY);
Vector2 posMin = origin + offset;
Vector2 posMax = posMin + dimensions;
UI.CreateButton(ref container, panelName, "0.2 0.2 0.2 0.7", name, 18, posMin.x + " " + posMin.y, posMax.x + " " + posMax.y, $"Choose_Class {kit}");
}
[ConsoleCommand("Choose_Class")]
void cmdChoose_Class(ConsoleSystem.Arg arg)
{
var player = arg.connection.player as BasePlayer;
if (player == null)
return;
CuiHelper.DestroyUi(player, "ClassSelector");
var className = arg.GetString(0).Replace("'", "");
bool noGear = false;
if (string.IsNullOrEmpty(player.GetComponent<EventPlayer>().currentClass)) noGear = true;
player.GetComponent<EventPlayer>().currentClass = className;
if (noGear) GivePlayerKit(player, null);
}
#endregion
#region Game Timer UI
private void StartTimer(int time)
{
AutoArenaTimers.Add(timer.Once(time, () => CancelEvent(GetMessage("TimeLimit"))));
PlayTimer = time;
foreach (var player in EventPlayers)
TimerCountdown(player.player);
}
private void TimerCountdown(BasePlayer player)
{
CuiHelper.DestroyUi(player, "PlayTimer");
if (EventStarted)
{
var timerElement = UI.CreateElementContainer("PlayTimer", "0.3 0.3 0.3 0.6", "0.45 0.91", "0.55 0.948", false);
TimeSpan dateDifference = TimeSpan.FromSeconds(PlayTimer);
string clock = string.Format("{0:D2}:{1:D2}", dateDifference.Minutes, dateDifference.Seconds);
UI.CreateLabel(ref timerElement, "PlayTimer", "", clock, 20, "0 0", "1 1");
CuiHelper.AddUi(player, timerElement);
PlayTimer--;
AutoArenaTimers.Add(timer.In(1, () => TimerCountdown(player)));
}
}
private void DestroyUI(BasePlayer player)
{
CuiHelper.DestroyUi(player, "ClassSelector");
CuiHelper.DestroyUi(player, "PlayTimer");
}
#endregion
#region Global Functions
bool hasAccess(ConsoleSystem.Arg arg)
{
if (arg.connection?.authLevel < 1)
{
SendReply(arg, GetMessage("MessagesPermissionsNotAllowed"));
return false;
}
return true;
}
static void TPPlayer(BasePlayer player, Vector3 destination)
{
if (player.net?.connection != null)
player.ClientRPCPlayer(null, player, "StartLoading", null, null, null, null, null);
ELog($"Teleporting {player.displayName} to {destination}");
StartSleeping(player);
player.MovePosition(destination);
if (player.net?.connection != null)
player.ClientRPCPlayer(null, player, "ForcePositionTo", destination);
player.TransformChanged();
if (player.net?.connection != null)
player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, true);
player.UpdateNetworkGroup();
player.SendNetworkUpdateImmediate(false);
if (player.net?.connection == null) return;
try { player.ClearEntityQueue(null); } catch { }
player.SendFullSnapshot();
}
static void StartSleeping(BasePlayer player)
{
if (player.IsSleeping())
return;
ELog($"Put {player.displayName} to sleep");
player.SetPlayerFlag(BasePlayer.PlayerFlags.Sleeping, true);
if (!BasePlayer.sleepingPlayerList.Contains(player))
BasePlayer.sleepingPlayerList.Add(player);
player.CancelInvoke("InventoryUpdate");
}
#endregion
#region Player Management
[HookMethod("TeleportAllPlayersToEvent")]
public void TeleportAllPlayersToEvent()
{
ELog("TeleportAllPlayersToEvent");
foreach (EventPlayer eventplayer in EventPlayers.ToArray())
TeleportPlayerToEvent(eventplayer.player);
}
void TeleportPlayerToEvent(BasePlayer player)
{
var eventPlayer = player.GetComponent<EventPlayer>();
if (eventPlayer == null || player.net?.connection == null) return;
ELog($"Tp2Event {player.displayName}");
var targetpos = Spawns.Call("GetRandomSpawn", EventSpawnFile);
if (targetpos is string)
return;
var newpos = Interface.Oxide.CallHook("EventChooseSpawn", player, targetpos);
if (newpos is Vector3)
targetpos = newpos;
if (newpos is bool)
if ((bool)newpos == false)
{
ELog($"Tp2Event {player.displayName} newpos is false");
timer.Once(3, () => TeleportPlayerToEvent(player));
return;
}
if (!configData.KillDeserters)
ZoneManager?.Call("AddPlayerToZoneKeepinlist", ZoneName, player);
TPPlayer(player, (Vector3)targetpos);
Interface.Oxide.CallHook("OnEventPlayerSpawn", player);
}
void SaveAllInventories()
{
ELog($"SaveAllInventories");
foreach (EventPlayer player in EventPlayers)
player?.SaveInventory();
}
void SaveAllPlayerStats()
{
ELog($"SaveAllStats");
foreach (EventPlayer player in EventPlayers)
player?.SaveHealth();
}
void SaveAllHomeLocations()
{
ELog($"SaveAllHomes");
foreach (EventPlayer player in EventPlayers)
player?.SaveHome();
}
void SetAllEventPlayers()
{
ELog($"SetAllPlayers");
foreach (EventPlayer player in EventPlayers)
SetEventPlayer(player);
}
void RedeemInventory(BasePlayer player)
{
EventPlayer eventplayer = player.GetComponent<EventPlayer>();
if (eventplayer == null) return;
ELog($"Redeem Inventory {player.displayName}");
if (player.IsDead() || player.health < 1)
{
ELog($"RI {player.displayName} is dead");
timer.Once(5, () => RedeemInventory(player));
return;
}
eventplayer.player.inventory.Strip();
if (eventplayer.savedInventory)
eventplayer.RestoreInventory();
}
void TeleportPlayerHome(BasePlayer player)
{
EventPlayer eventplayer = player.GetComponent<EventPlayer>();
if (eventplayer == null) return;
ELog($"TPPlayerHome {player.displayName}");
if (player.IsDead() || player.health < 1)
{
ELog($"TPPH {player.displayName} is dead");
return;
}
if (eventplayer.savedHome)
eventplayer.TeleportHome();
}
void TryErasePlayer(BasePlayer player)
{
var eventplayer = player.GetComponent<EventPlayer>();
if (eventplayer == null) return;
ELog($"TryErase {player.displayName}");
if (!(eventplayer.inEvent) && !(eventplayer.savedHome) && !(eventplayer.savedInventory))
{
ELog($"{player.displayName} !inevent/savedhome/savedinventory");
eventplayer.enabled = false;
EventPlayers.Remove(eventplayer);
UnityEngine.Object.Destroy(eventplayer);
}
}
[HookMethod("GivePlayerKit")]
public void GivePlayerKit(BasePlayer player, string GiveKit)
{
ELog($"give {player.displayName} kit");
player.inventory.Strip();
if (!AutoEventLaunched)
{
if (!UseClassSelection)
Kits.Call("GiveKit", player, GiveKit);
else
{
if (string.IsNullOrEmpty(player.GetComponent<EventPlayer>().currentClass))
SelectClass(player);
else GiveClassKit(player);
}
}
else
{
if (!configData.z_AutoEvents.z_AutoEventSetup[EventAutoNum].UseClassSelector)
Kits.Call("GiveKit", player, configData.z_AutoEvents.z_AutoEventSetup[EventAutoNum].Kit);
else
{
if (string.IsNullOrEmpty(player.GetComponent<EventPlayer>().currentClass))
SelectClass(player);
else GiveClassKit(player);
}
}
}
private void GiveClassKit(BasePlayer player)
{
ELog($"Give class kit {player.displayName}");
Kits.Call("GiveKit", player, player.GetComponent<EventPlayer>().currentClass);
Interface.Oxide.CallHook("OnPlayerSelectClass", player);
}
void EjectPlayer(BasePlayer player)
{
ELog($"Ejecting {player.displayName}");
if (player.IsAlive())
{
ELog($"Eject Alive {player.displayName}");
player.SetPlayerFlag(BasePlayer.PlayerFlags.Wounded, false);
player.CancelInvoke("WoundingEnd");
player.metabolism.bleeding.value = 0f;
}
if (!configData.KillDeserters)
if (!string.IsNullOrEmpty(ZoneName))
ZoneManager?.Call("RemovePlayerFromZoneKeepinlist", ZoneName, player);
player.GetComponent<EventPlayer>().inEvent = false;
Interface.Oxide.CallHook("DisableBypass", player.userID);
}
void RestorePlayerHealth(BasePlayer player)
{
ELog($"Restoring health {player.displayName}");
EventPlayer eventplayer = player.GetComponent<EventPlayer>();
if (eventplayer)
{
ELog($"RH {player.displayName} is event player");
player.health = eventplayer.health;
player.metabolism.calories.value = eventplayer.calories;
player.metabolism.hydration.value = eventplayer.hydration;
player.metabolism.bleeding.value = 0;
player.metabolism.SendChangesToClient();
}
}
#endregion
#region Event Management
[HookMethod("OpenEvent")]
public object OpenEvent()
{
if (EventOpen)
return $"{EventGameName} is already open";
ELog($"Opening Event {EventGameName}");
var success = Interface.Oxide.CallHook("CanEventOpen");
if (success is string)
return (string)success;
EventOpen = true;
EventPlayers = new List<EventPlayer>();
var name = EventGameName;
if (EventMode == GameMode.Battlefield)
name = "Battlefield - ";
BroadcastToChat(string.Format(GetMessage("MessagesEventOpen"), name));
Interface.Oxide.CallHook("OnEventOpenPost");
ELog($"Game type: {EventMode}");
ELog($"AutoEvent: {AutoEventLaunched}");
ELog($"{EventGameName} Successfully opened");
return true;
}
void OnEventOpenPost() => OnEventOpenPostAutoEvent();
void OnEventOpenPostAutoEvent()
{
if (!AutoEventLaunched) return;
ELog($"Start auto event timers");
DestroyTimers();
var autocfg = configData.z_AutoEvents;
if (autocfg.AutoCancel_Timer != 0)
AutoArenaTimers.Add(timer.Once(autocfg.AutoCancel_Timer, () => CancelEvent(GetMessage("NoPlayers"))));
AutoArenaTimers.Add(timer.Repeat(configData.AnnounceEvent_Interval, 0, AnnounceEvent));
}
object CanEventOpen()
{
if (EventGameName == null) return GetMessage("MessagesEventNotSet");
else if (EventSpawnFile == null) return GetMessage("MessagesEventNoSpawnFile");
else if (EventOpen) return GetMessage("MessagesEventAlreadyOpened");
object success = Spawns.Call("GetSpawnsCount", EventSpawnFile);
if (success is string)
return (string)success;
return null;
}
[HookMethod("CloseEvent")]
public object CloseEvent()
{
if (!EventOpen) return GetMessage("MessagesEventAlreadyClosed");
EventOpen = false;
Interface.Oxide.CallHook("OnEventClosePost");
if (EventStarted)
BroadcastToChat(GetMessage("MessagesEventClose"));
else
BroadcastToChat(GetMessage("MessagesEventCancel"));
return true;
}
object AutoEventNext()
{
ELog($"Next auto event");
if (configData.z_AutoEvents.z_AutoEventSetup.Count == 0)
{
ELog($"No events setup");
AutoEventLaunched = false;
return GetMessage("NoAuto");
}
bool successful = false;
for (int i = 0; i < configData.z_AutoEvents.z_AutoEventSetup.Count; i++)
{
EventAutoNum++;
if (EventAutoNum >= configData.z_AutoEvents.z_AutoEventSetup.Count) EventAutoNum = 0;
var autocfg = configData.z_AutoEvents.z_AutoEventSetup[EventAutoNum];
object success = SelectEvent(autocfg.GameType);
if (success is string) { continue; }
success = SelectSpawnfile(autocfg.Spawnfile);
if (success is string) { continue; }
success = SelectMinplayers(autocfg.MinimumPlayers);
if (success is string) { continue; }
success = SelectMaxplayers(autocfg.MaximumPlayers);
if (success is string) { continue; }
success = Interface.Oxide.CallHook("CanEventOpen");
if (success is string) { continue; }
if (!string.IsNullOrEmpty(autocfg.ZoneID))
ZoneName = autocfg.ZoneID;
successful = true;
break;
}
if (!successful)
{
ELog($"No events init");
return GetMessage("NoAutoInit");
}
ELog($"Auto init success");
AutoArenaTimers.Add(timer.Once(configData.z_AutoEvents.GameInterval, () => OpenEvent()));
return null;
}
void OnEventStartPost()
{
ELog($"Event starting");
DestroyTimers();
if (AutoEventLaunched)
OnEventStartPostAutoEvent();
else if (EventMode == GameMode.Battlefield)
StartTimer(configData.Battlefield_Timer);
if (configData.AnnounceDuring_Event)
AutoArenaTimers.Add(timer.Repeat(configData.AnnounceEvent_Interval, 0, () => AnnounceDuringEvent()));
}
void OnEventStartPostAutoEvent()
{
if (configData.z_AutoEvents.z_AutoEventSetup[EventAutoNum].TimeLimit != 0)
StartTimer(configData.z_AutoEvents.z_AutoEventSetup[EventAutoNum].TimeLimit);
}
void DestroyTimers()
{
ELog($"Destroying timers");
foreach (Timer eventtimer in AutoArenaTimers)
eventtimer.Destroy();
AutoArenaTimers.Clear();
}
void CancelEvent(string reason)
{
ELog($"Cancelling event");
var message = GetMessage("EventCancelled");
object success = Interface.Oxide.CallHook("OnEventCancel");
if (success != null)
{
if (success is string)
message = (string)success;
else
return;
}
BroadcastToChat(string.Format(message, EventGameName, reason));
DestroyTimers();
if (EventStarted)
EndEvent();
else if (AutoEventLaunched)
AutoEventNext();
}
void AnnounceEvent()
{
var message = GetMessage("EventOpen");
object success = Interface.Oxide.CallHook("OnEventAnnounce");
if (success is string)
{
message = (string)success;
}
BroadcastToChat(string.Format(message, EventGameName));
}
void AnnounceDuringEvent()
{
if (configData.AnnounceDuring_Event)
{
if (EventOpen && EventStarted)
{
var message = GetMessage("StillOpen");
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (!player.GetComponent<EventPlayer>())
SendReply(player, string.Format(message, EventGameName));
}
}
}
}
object LaunchEvent()
{
ELog($"Launching auto events");
AutoEventLaunched = true;
if (!EventStarted)
{
if (!EventOpen)
{
object success = AutoEventNext();
if (success is string)
return (string)success;
success = OpenEvent();
if (success is string)
return (string)success;
}
else OnEventOpenPostAutoEvent();
}
else OnEventStartPostAutoEvent();
ELog($"Launch successful");
return null;
}
[HookMethod("EndEvent")]
public object EndEvent()
{
if (EventEnded) return GetMessage("MessagesEventNoGamePlaying");
ELog($"Ending event");
foreach (var player in EventPlayers)
Interface.Oxide.CallHook("DestroyUI", player.player);
BroadcastToChat(string.Format(GetMessage("MessagesEventPEnd"), EventGameName));
EventOpen = false;
EventStarted = false;
EventPending = false;
EventEnded = true;
EnableGod();
BroadcastToChat(string.Format(GetMessage("MessagesEventEnd"), EventGameName));
Interface.Oxide.CallHook("OnEventEndPre");
ProcessPlayers();
return true;
}
void ProcessPlayers()
{
ELog($"Processing players");
for (int i = 0; i < EventPlayers.Count; i++)
RestorePlayer(EventPlayers[i]);
timer.Once(5, () =>
{
if (EventPlayers.Count > 0)
{
ELog($"EventPlayers.Count > 0, count is {EventPlayers.Count}");
ProcessPlayers();
return;
}
ELog($"EventPlayers.Count is 0");
DestroyGame();
Interface.Oxide.CallHook("OnEventEndPost");
});
}
void RestorePlayer(EventPlayer p)
{
if (p == null) return;
ELog($"Restoring {p.player.displayName}");
if (p.player.IsDead() || !p.player.IsAlive())
{
ELog($"RP {p.player.displayName} is dead");
var pos = Spawns.Call("GetRandomSpawn", EventSpawnFile);
if (pos is Vector3) p.player.RespawnAt((Vector3)pos, new Quaternion());
else p.player.Respawn();
return;
}
if (p.player.IsWounded() || p.player.health < 2)
{
ELog($"RP {p.player.displayName} is wounded");
p.player.SetPlayerFlag(BasePlayer.PlayerFlags.Wounded, false);
RestorePlayerHealth(p.player);
return;
}
if (p.player.IsSleeping())
{
ELog($"RP {p.player.displayName} is sleeping");
p.player.EndSleeping();
return;
}
ELog($"Starting restoration of {p.player.displayName}");
p.RestoreInventory();
p.TeleportHome();
RestorePlayerHealth(p.player);
Godmode.Remove(p.player.userID);
if (!p.savedHome && !p.savedInventory)
{
ELog($"{p.player.displayName} has no saved home or inv, try erase");
EjectPlayer(p.player);
TryErasePlayer(p.player);
}
}
void EnableGod()
{
Godmode = new List<ulong>();
foreach (EventPlayer player in EventPlayers)
{
ELog($"Godmode added {player.player.displayName}");
Godmode.Add(player.player.userID);
player.player.metabolism.bleeding.value = 0;
player.player.metabolism.SendChangesToClient();
}
}
void DisableGod()
{
Godmode.Clear();
}
void DestroyGame()
{
ELog($"Destroying game");
DestroyTimers();
EventPlayers.Clear();
// ... [Code preview truncated due to length. Full source in attached file] ...