C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using Rust;
using UnityEngine;
using System.Linq;
namespace Oxide.Plugins {
[Info("Джаггернаут", "k1lly0u", "0.1.9", ResourceId = 0)]
internal class Juggernaut : RustPlugin {
#region Fields
[PluginReference]
Plugin Clans;
[PluginReference]
Plugin Friends;
[PluginReference]
Plugin LustyMap;
[PluginReference]
Plugin EventManager;
[PluginReference]
Plugin ServerRewards;
[PluginReference]
Plugin Economics;
static Juggernaut ins;
StoredData storedData;
private DynamicConfigFile data;
private BasePlayer juggernaut = null;
private SphereEntity finalSphere = null;
private Vector3 endPos = Vector3.zero;
private Timer nextMatch;
private Timer startMatch;
private Timer eventTimer;
private Timer broadcastTimer;
private Timer openMessage;
private Timer uiTimer;
private double eventEnd;
private double nextTrigger;
private string juggernautIcon;
private bool isOpen;
private bool hasStarted;
private bool initialized;
private bool hasDestinations;
private List<ulong> optedIn = new List<ulong>();
private Dictionary<ulong, Destinations> destinationCreator = new Dictionary<ulong, Destinations>();
private const string sphereEnt = "assets/prefabs/visualization/sphere.prefab";
#endregion
#region Oxide Hooks
void Loaded() {
permission.RegisterPermission("juggernaut.canbe", this);
lang.RegisterMessages(Messages, this);
data = Interface.Oxide.DataFileSystem.GetFile("juggernaut_data");
}
void OnServerInitialized() {
ins = this;
LoadVariables();
LoadData();
if (storedData.destinations.Count > 0) {
hasDestinations = true;
StartEventTimer();
}
else PrintWarning("Назначений нет! Не удалось запустить ивент");
initialized = true;
}
void Unload() {
if (eventTimer != null) eventTimer.Destroy();
if (nextMatch != null) nextMatch.Destroy();
if (startMatch != null) startMatch.Destroy();
if (openMessage != null) openMessage.Destroy();
if (uiTimer != null) uiTimer.Destroy();
if (broadcastTimer != null) broadcastTimer.Destroy();
foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Main);
CuiHelper.DestroyUi(juggernaut, Compass);
if (juggernaut != null && hasStarted) {
UnlockInventory(juggernaut);
juggernaut.inventory.Strip();
DestroyEvent();
}
}
void OnPlayerInit(BasePlayer player) {
if (player.IsSleeping() || player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot)) {
timer.In(1, () => OnPlayerInit(player));
return;
}
if (storedData.unrestoredPlayers.ContainsKey(player.userID)) TryRestorePlayer(player);
}
void OnPlayerDisconnected(BasePlayer player) {
if (optedIn.Contains(player.userID)) optedIn.Remove(player.userID);
if (player == juggernaut && hasStarted) {
UnlockInventory(player);
player.inventory.Strip();
DestroyEvent();
}
}
void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
if (entity == null || info == null) return;
var victim = entity.ToPlayer();
var attacker = info.InitiatorPlayer;
if (victim != null && victim == juggernaut) {
if (info.Initiator != null && info.Initiator.ShortPrefabName.Equals("beartrap") && configData.JuggernautSettings.DisableBeartrapDamage) {
info.damageTypes.ScaleAll(0);
return;
}
if (info.WeaponPrefab != null && info.WeaponPrefab.ShortPrefabName.Equals("landmine") && configData.JuggernautSettings.DisableLandmineDamage) {
info.damageTypes.ScaleAll(0);
return;
}
if (info.damageTypes.GetMajorityDamageType() == DamageType.Fall && configData.JuggernautSettings.DisableFallDamage) {
info.damageTypes.ScaleAll(0);
return;
}
if (attacker != null) {
if (IsFriend(victim.userID, attacker.userID)) {
info.damageTypes.ScaleAll(0);
SendReply(attacker, msg("<color=white>Вы не можете навредить своим друзьям, когда они являются Джаггернаутом!</color>", attacker.UserIDString));
return;
}
if (IsClanmate(victim.userID, attacker.userID)) {
info.damageTypes.ScaleAll(0);
SendReply(attacker, msg("<color=white>Вы не можете навредить своим соклановцем, когда они являются Джаггернаутом!</color>", attacker.UserIDString));
return;
}
}
info.damageTypes.ScaleAll(configData.JuggernautSettings.DefenseDamageModifier);
return;
}
if (attacker == null) return;
if (attacker == juggernaut) {
if (!configData.JuggernautSettings.CanDamageStructures && (entity is BuildingBlock || entity is SimpleBuildingBlock)) {
info.damageTypes.ScaleAll(0);
return;
}
info.damageTypes.ScaleAll(configData.JuggernautSettings.AttackDamageModifier);
}
}
void OnEntitySpawned(BaseNetworkable entity) {
if (!initialized || entity == null) return;
var player = entity as BasePlayer;
if (player != null) {
TryRestorePlayer(player);
}
}
void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
if (entity == null || info == null) return;
var victim = entity.ToPlayer();
if (victim == null) return;
if (victim == juggernaut) {
if (eventTimer != null) eventTimer.Destroy();
if (uiTimer != null) uiTimer.Destroy();
if (broadcastTimer != null) broadcastTimer.Destroy();
foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Main);
CuiHelper.DestroyUi(juggernaut, Compass);
if (!configData.Prizes.UseJuggernautInventory) victim.inventory.Strip();
var attacker = info.InitiatorPlayer;
if (attacker != null) {
if (victim == info.InitiatorPlayer) {
victim.inventory.Strip();
PrintToChat(msg("<color=white>Джаггернаут совершил самоубийство! Ивент завершён и награда удалена</color>"));
}
else if (!IsFriend(victim.userID, attacker.userID) && !IsClanmate(victim.userID, attacker.userID)) {
PrintToChat(msg("<color=orange>[Джаггернаут]</color><color=white> : Джаггернаут был убить, теперь можно забрать выигрыш с него!</color>"));
if (configData.Prizes.MoneyRewardAmount > 0) {
if (configData.Prizes.UseEconomics) Economics?.Call("Deposit", attacker.userID, (double)configData.Prizes.MoneyRewardAmount);
if (configData.Prizes.UseServerRewards) ServerRewards?.Call("AddPoints", attacker.userID, configData.Prizes.MoneyRewardAmount);
}
}
}
else PrintToChat(msg("<color=orange>[Джаггернаут]</color><color=white> : Джаггернаут был убить, теперь можно забрать выигрыш с него!</color>"));
UnlockInventory(victim);
juggernaut = null;
UnityEngine.Object.Destroy(finalSphere.GetComponent<FinalSphere>());
}
}
object CanNetworkTo(BaseEntity entity, BasePlayer target) {
if (finalSphere != null && entity == finalSphere && juggernaut != null) {
if (target != juggernaut) return false;
}
return null;
}
object OnRunCommand(ConsoleSystem.Arg arg) {
if (!hasStarted || arg.Connection == null || arg.Connection.player == null || arg.cmd.Name != "kill") return null;
var player = arg.Connection.player as BasePlayer;
if (player == null) return null;
if (player == juggernaut) {
SendReply(player, msg("<color=white>Вы не можете совершить самоубийство, пока вы являетесь Джаггернаутом!</color>", player.UserIDString));
return true;
}
return null;
}
#endregion
#region Functions
void LockInventory(BasePlayer player) {
if (!player.inventory.containerMain.HasFlag(ItemContainer.Flag.IsLocked)) player.inventory.containerMain.SetFlag(ItemContainer.Flag.IsLocked, true);
if (!player.inventory.containerBelt.HasFlag(ItemContainer.Flag.IsLocked)) player.inventory.containerBelt.SetFlag(ItemContainer.Flag.IsLocked, true);
if (!player.inventory.containerWear.HasFlag(ItemContainer.Flag.IsLocked)) player.inventory.containerWear.SetFlag(ItemContainer.Flag.IsLocked, true);
}
void UnlockInventory(BasePlayer player) {
if (player.inventory.containerMain.HasFlag(ItemContainer.Flag.IsLocked)) player.inventory.containerMain.SetFlag(ItemContainer.Flag.IsLocked, false);
if (player.inventory.containerBelt.HasFlag(ItemContainer.Flag.IsLocked)) player.inventory.containerBelt.SetFlag(ItemContainer.Flag.IsLocked, false);
if (player.inventory.containerWear.HasFlag(ItemContainer.Flag.IsLocked)) player.inventory.containerWear.SetFlag(ItemContainer.Flag.IsLocked, false);
}
void StartEventTimer() {
optedIn.Clear();
UnsubscribeHooks();
nextMatch = timer.Once(configData.EventTimers.TimeBetweenEvents, CheckConditions);
nextTrigger = GrabCurrentTime() + configData.EventTimers.TimeBetweenEvents;
}
void CheckConditions() {
if (BasePlayer.activePlayerList.Count >= configData.EventConditions.MinimumPlayersToOpen) OpenEvent();
}
void OpenEvent() {
if (string.IsNullOrEmpty(juggernautIcon) && configData.UISettings.ShowUITimer && !string.IsNullOrEmpty(configData.UISettings.IconUrl)) Add(configData.UISettings.IconUrl);
isOpen = true;
startMatch = timer.Once(configData.EventTimers.TimeBeforeSelection, StartEvent);
openMessage = timer.Repeat(45, 0, () => PrintToChat(msg("<color=orange>[Джаггернаут] </color><color=white>: Ивент Джаггернаут открыт! Введите </color><color=#ffd479>/jug join</color><color=white> чтобы записаться на ивент, и возможно стать Джаггернаутом</color>")));
nextTrigger = configData.EventTimers.TimeBeforeSelection + GrabCurrentTime();
PrintToChat(msg("<color=orange>[Джаггернаут] </color><color=white>: Ивент Джаггернаут открыт! Введите </color><color=#ffd479>/jug join</color><color=white> чтобы записаться на ивент, и возможно стать Джаггернаутом</color>"));
}
void StartEvent() {
isOpen = false;
if (openMessage != null) openMessage.Destroy();
if (optedIn.Count == 0) {
PrintToChat(msg("<color=orange>[Джаггернаут]</color><color=white> : Ни один игрок не записался на ивент.Ивент отменен!</color>"));
StartEventTimer();
return;
}
var minEntrants = (int)Math.Round(BasePlayer.activePlayerList.Count * configData.EventConditions.PercentageEntrantsToStart, 0);
if (optedIn.Count < minEntrants) {
PrintToChat(string.Format(msg("notEnoughEntrants"), $"{configData.EventConditions.PercentageEntrantsToStart * 100}%"));
StartEventTimer();
return;
}
SubscribeHooks();
ulong playerId = optedIn.GetRandom();
var player = BasePlayer.activePlayerList.FirstOrDefault(x => x.userID == playerId);
if (player == null) return;
var destinations = storedData.destinations.GetRandom();
endPos = new Vector3(destinations.x2, destinations.y2, destinations.z2);
StorePlayer(player);
player.inventory.Strip();
MovePosition(player, new Vector3(destinations.x1, destinations.y1, destinations.z1));
PrepareJuggernaut(player);
CreateSphere();
eventEnd = configData.EventTimers.TimeToCompleteJourney + GrabCurrentTime();
nextTrigger = configData.EventTimers.TimeToCompleteJourney + GrabCurrentTime();
hasStarted = true;
}
void PrepareJuggernaut(BasePlayer player) {
if (player.IsSleeping() || player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot)) {
timer.In(1, () => PrepareJuggernaut(player));
return;
}
juggernaut = player;
if (configData.JuggernautSettings.StartWithFullMetabolism) {
player.metabolism.Reset();
player.health = player.MaxHealth();
player.metabolism.hydration.value = player.metabolism.hydration.max;
player.metabolism.calories.value = player.metabolism.calories.max;
player.metabolism.SendChangesToClient();
}
GiveJuggernautGear();
PrintToChat(string.Format(msg("<color=orange>[Джаггернаут] </color><color=white>: Джаггернаут приближается к </color><color=#ffd479>{0}</color><color=white>! Найдите и убейте его до того, как он доберется до места назначения!</color>"), $"X:{Math.Round(endPos.x, 1)}, Z:{Math.Round(endPos.z, 1)}"));
SendReply(player, string.Format(msg("<color=orange>[Джаггернаут]</color><color=white> : Вы должны дойти до </color><color=#ffd479>{0}</color><color=white> и войти в белую сферу, чтобы выиграть ивент!</color>", player.UserIDString), $"X:{Math.Round(endPos.x, 1)}, Z:{Math.Round(endPos.z, 1)}"));
eventTimer = timer.In(configData.EventTimers.TimeToCompleteJourney, EventCancel);
if (configData.UISettings.ShowUITimer) RefreshAllUI();
if (configData.LustyMapIntegration.ShowDestinationIcon) {
if (configData.LustyMapIntegration.DestinationAmount > 1 && storedData.destinations.Count >= configData.LustyMapIntegration.DestinationAmount) {
var destinations = new List<Destinations>(storedData.destinations);
var randomNumber = UnityEngine.Random.Range(1, configData.LustyMapIntegration.DestinationAmount);
for (int i = 0; i < configData.LustyMapIntegration.DestinationAmount; i++) {
if (i == randomNumber) {
AddMapMarker(endPos.x, endPos.z, $"{msg("possibleDest")} {i + 1}");
}
else {
var destination = destinations.GetRandom();
destinations.Remove(destination);
AddMapMarker(destination.x2, destination.z2, $"{msg("possibleDest")} {i + 1}");
}
}
}
else AddMapMarker(endPos.x, endPos.z, msg("destination"));
}
if (configData.GameOptions.BroadcastJuggernautPositionEvery > 0) {
broadcastTimer = timer.Repeat(configData.GameOptions.BroadcastJuggernautPositionEvery, 0, () => {
if (juggernaut != null) {
if (configData.GameOptions.BroadcastToLustyMap) {
AddMapMarker(juggernaut.transform.position.x, juggernaut.transform.position.z, msg("juggernaut"));
timer.In(configData.GameOptions.SecondsToDisplayOnLM, () => RemoveMapMarker(msg("juggernaut")));
}
else PrintToChat(string.Format(msg("<color=white>Джаггернаута видели в последний раз на координатах</color> <color=#ffd479>X:{0}, Z:{1}</color>"), Math.Round(juggernaut.transform.position.x, 1), Math.Round(juggernaut.transform.position.z, 1)));
}
}
);
}
}
void EventCancel() {
PrintToChat(msg("<color=orange>[Джаггернаут]</color><color=white> : Ивент окончен, потому что Джаггернаут не успел добраться до точки назначения</color>"));
TryRestorePlayer(juggernaut);
DestroyEvent();
}
void EventWin() {
PrintToChat(msg("<color=orange>[Джаггернаут]</color><color=white> : Джаггернаут добрался до точки назначения и выиграл этот ивент!"));
if (configData.Prizes.UseJuggernautInventory) {
var remainingItems = new List<EventInvItem>();
remainingItems.AddRange(GetItems(juggernaut.inventory.containerBelt));
remainingItems.AddRange(GetItems(juggernaut.inventory.containerMain));
remainingItems.AddRange(GetItems(juggernaut.inventory.containerWear));
if (!storedData.winnerRewards.ContainsKey(juggernaut.userID)) storedData.winnerRewards.Add(juggernaut.userID, remainingItems);
else storedData.winnerRewards[juggernaut.userID] = remainingItems;
}
if (configData.Prizes.UseServerRewards || configData.Prizes.UseEconomics) {
if (!storedData.winnerMoney.ContainsKey(juggernaut.userID)) storedData.winnerMoney.Add(juggernaut.userID, new List<Points>());
storedData.winnerMoney[juggernaut.userID].Add(new Points {
isRp = configData.Prizes.UseServerRewards, amount = configData.Prizes.MoneyRewardAmount
}
);
}
TryRestorePlayer(juggernaut);
DestroyEvent();
}
void DestroyEvent() {
hasStarted = false;
if (eventTimer != null) eventTimer.Destroy();
if (uiTimer != null) uiTimer.Destroy();
if (broadcastTimer != null) broadcastTimer.Destroy();
foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Main);
CuiHelper.DestroyUi(juggernaut, Compass);
juggernaut = null;
UnityEngine.Object.Destroy(finalSphere.GetComponent<FinalSphere>());
SaveData();
if (configData.GameOptions.BroadcastJuggernautPositionEvery > 0 && configData.GameOptions.BroadcastToLustyMap) RemoveMapMarker(msg("juggernaut"));
if (configData.LustyMapIntegration.ShowDestinationIcon) {
if (configData.LustyMapIntegration.DestinationAmount > 1) {
for (int i = 0; i < configData.LustyMapIntegration.DestinationAmount; i++) {
RemoveMapMarker($"{msg("possibleDest")} {i + 1}");
}
}
else RemoveMapMarker(msg("destination"));
}
StartEventTimer();
}
void TryRestorePlayer(BasePlayer player) {
player.inventory.Strip();
UnlockInventory(player);
PlayerData data;
if (storedData.unrestoredPlayers.TryGetValue(player.userID, out data)) {
MovePosition(player, new Vector3(data.x, data.y, data.z));
RestorePlayer(player, data);
}
}
void GiveJuggernautGear() {
foreach (var entry in configData.JuggernautSettings.Inventory) {
Item item = ItemManager.CreateByName(entry.Shortname, entry.Amount, entry.SkinID);
item.MoveToContainer(entry.Container == "wear" ? juggernaut.inventory.containerWear : entry.Container == "belt" ? juggernaut.inventory.containerBelt : juggernaut.inventory.containerMain);
}
LockInventory(juggernaut);
}
void UnsubscribeHooks() {
Unsubscribe(nameof(OnEntityTakeDamage));
Unsubscribe(nameof(OnEntityDeath));
Unsubscribe(nameof(CanNetworkTo));
}
void SubscribeHooks() {
Subscribe(nameof(OnEntityTakeDamage));
Subscribe(nameof(OnEntityDeath));
Subscribe(nameof(CanNetworkTo));
}
double GrabCurrentTime() => DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
#endregion
#region Teleportation Management
private void MovePosition(BasePlayer player, Vector3 destination) {
if (player.net?.connection != null) player.ClientRPCPlayer(null, player, "StartLoading", null, null, null, null, null);
StartSleeping(player);
player.MovePosition(destination);
if (player.net?.connection != null) player.ClientRPCPlayer(null, player, "ForcePositionTo", destination);
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();
}
private void StartSleeping(BasePlayer player) {
if (player.IsSleeping()) return;
player.SetPlayerFlag(BasePlayer.PlayerFlags.Sleeping, true);
if (!BasePlayer.sleepingPlayerList.Contains(player)) BasePlayer.sleepingPlayerList.Add(player);
player.CancelInvoke("InventoryUpdate");
}
#endregion
#region Player Saving and Restoration
private void StorePlayer(BasePlayer player) {
PlayerData data = new PlayerData {
inventory = new Dictionary<string, List<EventInvItem>> {
{
"belt", GetItems(player.inventory.containerBelt).ToList()
}
, {
"main", GetItems(player.inventory.containerMain).ToList()
}
, {
"wear", GetItems(player.inventory.containerWear).ToList()
}
}
, health = player.Health(), calories = player.metabolism.calories.value, hydration = player.metabolism.hydration.value, x = player.transform.position.x, y = player.transform.position.y, z = player.transform.position.z
}
;
if (!storedData.unrestoredPlayers.ContainsKey(player.userID)) storedData.unrestoredPlayers.Add(player.userID, data);
else storedData.unrestoredPlayers[player.userID] = data;
SaveData();
}
private IEnumerable<EventInvItem> GetItems(ItemContainer container) {
return container.itemList.Select(item => new EventInvItem {
itemid = item.info.itemid, amount = item.amount, ammo = (item.GetHeldEntity() as BaseProjectile)?.primaryMagazine.contents ?? 0, ammotype = (item.GetHeldEntity() as BaseProjectile)?.primaryMagazine.ammoType.shortname ?? null, skin = item.skin, condition = item.condition, instanceData = item.instanceData ?? null, contents = item.contents?.itemList.Select(item1 => new EventInvItem {
itemid = item1.info.itemid, amount = item1.amount, condition = item1.condition
}
).ToArray()
}
);
}
private void RestorePlayer(BasePlayer player, PlayerData data) {
if (player == null) return;
if (player.IsSleeping() || player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot)) {
timer.In(1, () => RestorePlayer(player, data));
return;
}
if (data == null) return;
RestorePlayerStats(player, data.health, data.hydration, data.calories);
RestoreItems(player, "wear", data.inventory["wear"]);
RestoreItems(player, "belt", data.inventory["belt"]);
RestoreItems(player, "main", data.inventory["main"]);
if (storedData.unrestoredPlayers.ContainsKey(player.userID)) {
storedData.unrestoredPlayers.Remove(player.userID);
SaveData();
}
}
private void RestorePlayerStats(BasePlayer player, float health, float hydration, float calories) {
player.metabolism.Reset();
player.health = health;
player.metabolism.calories.value = calories;
player.metabolism.hydration.value = hydration;
player.metabolism.bleeding.value = 0;
player.metabolism.SendChangesToClient();
}
private void SendPlayerHome(BasePlayer player, Vector3 position) => MovePosition(player, position);
private void RestoreItems(BasePlayer player, string targetContainer, List<EventInvItem> items) {
ItemContainer container = targetContainer == "belt" ? player.inventory.containerBelt : targetContainer == "wear" ? player.inventory.containerWear : player.inventory.containerMain;
for (int i = 0; i < container.capacity; i++) {
var existingItem = container.GetSlot(i);
if (existingItem != null) {
existingItem.RemoveFromContainer();
existingItem.Remove(0f);
}
if (items.Count > i) {
var itemData = items[i];
var item = ItemManager.CreateByItemID(itemData.itemid, itemData.amount, itemData.skin);
item.condition = itemData.condition;
if (itemData.instanceData != null) item.instanceData = itemData.instanceData;
var weapon = item.GetHeldEntity() as BaseProjectile;
if (weapon != null) {
if (!string.IsNullOrEmpty(itemData.ammotype)) weapon.primaryMagazine.ammoType = ItemManager.FindItemDefinition(itemData.ammotype);
weapon.primaryMagazine.contents = itemData.ammo;
}
if (itemData.contents != null) {
foreach (var contentData in itemData.contents) {
var newContent = ItemManager.CreateByItemID(contentData.itemid, contentData.amount);
if (newContent != null) {
newContent.condition = contentData.condition;
newContent.MoveToContainer(item.contents);
}
}
}
item.position = i;
item.SetParent(container);
}
}
}
#endregion
#region Sphere Creation
private void CreateSphere() {
finalSphere = (SphereEntity)GameManager.server.CreateEntity(sphereEnt, endPos, new Quaternion(), true);
finalSphere.currentRadius = 5;
finalSphere.lerpSpeed = 0;
finalSphere.enableSaving = false;
finalSphere.Spawn();
finalSphere.gameObject.AddComponent<FinalSphere>();
}
//[ChatCommand("jugs")]
//void cmdjugs(BasePlayer player, string command, string[] args)
//{
// OpenEvent();
// optedIn.Add(player.userID);
// StartEvent();
//}
class FinalSphere : MonoBehaviour {
public BaseEntity entity;
void Awake() {
entity = GetComponent<BaseEntity>();
gameObject.layer = (int)Layer.Reserved1;
gameObject.name = $"Juggernaut Final Zone";
enabled = false;
var collider = entity.gameObject.AddComponent<SphereCollider>();
collider.isTrigger = true;
collider.radius = 0.5f;
}
void OnDestroy() {
if (!entity.IsDestroyed) entity.Kill();
}
void OnTriggerEnter(Collider obj) {
if (obj.gameObject.layer == (int)Layer.Player_Server) {
var player = obj?.GetComponentInParent<BasePlayer>();
if (player != null) {
if (player == ins.juggernaut) {
ins.EventWin();
}
}
}
}
}
#endregion
#region Hooks
#region Internal Checks
private bool IsClanmate(ulong playerId, ulong friendId) {
if (!Clans) return false;
object playerTag = Clans?.Call("GetClanOf", playerId);
object friendTag = Clans?.Call("GetClanOf", friendId);
if (playerTag is string && friendTag is string) if (playerTag == friendTag) return true;
return false;
}
private bool IsFriend(ulong playerID, ulong friendID) {
if (!Friends) return false;
return (bool)Friends?.Call("IsFriend", playerID, friendID);
}
private bool IsPlaying(BasePlayer player) {
if (!EventManager) return false;
return (bool)EventManager.Call("isPlaying", player);
}
private void AddMapMarker(float x, float z, string markerName) => LustyMap?.Call("AddMarker", x, z, markerName, configData.UISettings.IconUrl);
private void RemoveMapMarker(string markerName) => LustyMap?.Call("RemoveMarker", markerName);
#endregion
#region External Checks
object CanTrade(BasePlayer player) {
if (player == juggernaut) return msg("Вы не можете обмениваться, пока вы являетесь Джаггернаутом!", player.UserIDString);
return null;
}
object canRemove(BasePlayer player) {
if (player == juggernaut) return msg("Вы не можете пользоваться ремувом, пока вы являетесь Джаггернаутом!", player.UserIDString);
return null;
}
object CanTeleport(BasePlayer player) {
if (player == juggernaut) return msg("Вы не можете телепортироваться, пока вы являетесь Джаггернаутом!", player.UserIDString);
return null;
}
object canShop(BasePlayer player) {
if (player == juggernaut) return msg("Вы не можете зайти в магазин, пока вы являетесь Джаггернаутом!", player.UserIDString);
return null;
}
#endregion
#endregion
#region UI
public class UI {
static public CuiElementContainer CreateElementContainer(string panelName, string color, string aMin, string aMax, bool useCursor = false) {
var NewElement = new CuiElementContainer() {
{
new CuiPanel {
Image = {
Color = color
}
, RectTransform = {
AnchorMin = aMin, AnchorMax = aMax
}
, CursorEnabled = useCursor
}
, new CuiElement().Parent = "Hud", panelName
}
}
;
return NewElement;
}
static public void AddImage(ref CuiElementContainer container, string panel, string png, string aMin, string aMax, float fadeOut = 0f) {
container.Add(new CuiElement {
Name = CuiHelper.GetGuid(), Parent = panel, Components = {
new CuiRawImageComponent {
Png = png, Sprite = "assets/content/textures/generic/fulltransparent.tga"
}
, new CuiRectTransformComponent {
AnchorMin = aMin, AnchorMax = aMax
}
}
}
);
}
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);
}
public static string Color(string hexColor, float alpha) {
if (hexColor.StartsWith("#")) hexColor = hexColor.TrimStart('#');
int red = int.Parse(hexColor.Substring(0, 2), NumberStyles.AllowHexSpecifier);
int green = int.Parse(hexColor.Substring(2, 2), NumberStyles.AllowHexSpecifier);
int blue = int.Parse(hexColor.Substring(4, 2), NumberStyles.AllowHexSpecifier);
return $"{(double)red / 255} {(double)green / 255} {(double)blue / 255} {alpha}";
}
}
#endregion
#region UI Creation
private const string Main = "JuggernautMain";
private const string Compass = "JuggernautCompass";
private void CreateTimerUI(BasePlayer player) {
var MainCont = UI.CreateElementContainer(Main, UI.Color(configData.UISettings.UIBackgroundColor, configData.UISettings.UIOpacity), $"{configData.UISettings.TimerPosition.XPosition} {configData.UISettings.TimerPosition.YPosition}", $"{configData.UISettings.TimerPosition.XPosition + configData.UISettings.TimerPosition.XDimension} {configData.UISettings.TimerPosition.YPosition + configData.UISettings.TimerPosition.YDimension}");
if (!string.IsNullOrEmpty(juggernautIcon)) UI.AddImage(ref MainCont, Main, juggernautIcon, "0.01 0.05", "0.425 0.95");
UI.CreateLabel(ref MainCont, Main, "", GetFormatTime(eventEnd), 15, "0.5 0", "1 1", TextAnchor.MiddleLeft);
CuiHelper.DestroyUi(player, Main);
CuiHelper.AddUi(player, MainCont);
}
private string GetFormatTime(double timeLeft) {
var time = timeLeft - GrabCurrentTime();
double minutes = Math.Floor((double)(time / 60));
time -= (int)(minutes * 60);
return string.Format("{0:00}:{1:00}", minutes, time);
}
private void RefreshAllUI() {
uiTimer = timer.Repeat(1, (int)(eventEnd - GrabCurrentTime()) - 1, () => {
foreach (var player in BasePlayer.activePlayerList) CreateTimerUI(player);
if (configData.UISettings.ShowCoordsToJuggernaut) ShowCompass();
}
);
}
private void ShowCompass() {
var MainCont = UI.CreateElementContainer(Compass, UI.Color(configData.UISettings.UIBackgroundColor, configData.UISettings.UIOpacity), $"{configData.UISettings.CompassPosition.XPosition} {configData.UISettings.CompassPosition.YPosition}", $"{configData.UISettings.CompassPosition.XPosition + configData.UISettings.CompassPosition.XDimension} {configData.UISettings.CompassPosition.YPosition + configData.UISettings.CompassPosition.YDimension}");
UI.CreateLabel(ref MainCont, Compass, "", $"{msg("target", juggernaut.UserIDString)} X: {Math.Round(endPos.x, 1)}, Z: {Math.Round(endPos.z, 1)}", 10, "0.05 0.5", "0.95 0.95", TextAnchor.MiddleLeft);
UI.CreateLabel(ref MainCont, Compass, "", $"{msg("current", juggernaut.UserIDString)} X: {Math.Round(juggernaut.transform.position.x, 1)}, Z: {Math.Round(juggernaut.transform.position.z, 1)}", 10, "0.05 0.05", "0.95 0.5", TextAnchor.MiddleLeft);
CuiHelper.DestroyUi(juggernaut, Compass);
CuiHelper.AddUi(juggernaut, MainCont);
}
#endregion
#region Imagery
private MemoryStream stream = new MemoryStream();
private WWW info;
public void Add(string url) {
info = new WWW(url);
TryDownloadImage();
}
void TryDownloadImage() {
if (!info.isDone) {
timer.In(1, TryDownloadImage);
return;
}
if (!string.IsNullOrEmpty(info.error)) {
PrintError(string.Format("Failed to load the Juggernaut icon! Error: {0}", info.error));
return;
}
else {
stream.Position = 0;
stream.SetLength(0);
stream.Write(info.bytes, 0, info.bytes.Length);
juggernautIcon = FileStorage.server.Store(stream, FileStorage.Type.png, CommunityEntity.ServerInstance.net.ID).ToString();
stream = null;
}
}
#endregion
#region Commands
[ChatCommand("jug")]
void cmdJuggernaut(BasePlayer player, string command, string[] args) {
if (args.Length == 0) {
SendReply(player, $"<size=22><color=orange>{Title}</color></size>");
SendReply(player, msg("<color=#ffd479>/jug info</color><color=white> - Показывать время, оставшееся до: начало ивента, окончание ивента в зависимости от текущего состояния ивента</color>", player.UserIDString));
SendReply(player, msg("<color=#ffd479>/jug join</color><color=white> - Позволяет игроку записаться на жеребьевку, чтобы попробовать стать Джаггернаутом</color>", player.UserIDString));
SendReply(player, msg("<color=#ffd479>/jug leave</color><color=white> - Удаляет игрока из жеребьевки, на становление Джаггернаутом</color>", player.UserIDString));
SendReply(player, msg("<color=#ffd479>/jug claim</color><color=white> - Используется Джаггернаутом, выигравшим ивент (гарантировать наличие пустых ячеек в инвентаре при подаче заявки!)</color>", player.UserIDString));
SendReply(player, msg("<color=#ffd479>/jug restore</color><color=white> - Используется для восстановления Джаггернаута после ивента, только если что-то случится с автоматизацией</color>", player.UserIDString));
if (player.IsAdmin) {
SendReply(player, msg("<color=#ffd479>/jug open</color><color=white> - Принудительное открытие ивента</color>", player.UserIDString));
SendReply(player, msg("<color=#ffd479>/jug start</color><color=white> - Принудительное начало ивента</color>", player.UserIDString));
SendReply(player, msg("<color=#ffd479>/jug cancel</color><color=white> - Принудительное отключение ивента</color>", player.UserIDString));
SendReply(player, msg("<color=#ffd479>/jug destination</color><color=white> - Используется для создания адресатов для Джаггернаута</color>", player.UserIDString));
}
return;
}
switch (args[0].ToLower()) {
case "info" : string time = GetFormatTime(nextTrigger);
if (hasStarted) SendReply(player, string.Format(msg($"<color=white>Ивент закончится через : </color><color=#ffd479>{time}</color>", player.UserIDString), time));
else if (isOpen) SendReply(player, string.Format(msg($"<color=white>Ивент начнется через : </color><color=#ffd479>{time}</color>", player.UserIDString), time));
else SendReply(player, string.Format(msg($"<color=white>Следующий ивент начнется через : </color><color=#ffd479>{time}</color>", player.UserIDString), time));
return;
case "join" : if (!permission.UserHasPermission(player.UserIDString, "juggernaut.canbe")) {
SendReply(player, msg("noPerms", player.UserIDString));
return;
}
if (!isOpen) {
SendReply(player, msg("<color=white>На данный момент нет открытого ивента</color>", player.UserIDString));
return;
}
if (IsPlaying(player)) {
SendReply(player, msg("<color=white>Вы не можете присоединиться к ивенту Джаггернаут, во время игры на Event Manager</color>", player.UserIDString));
return;
}
if (!optedIn.Contains(player.userID)) {
optedIn.Add(player.userID);
SendReply(player, msg("<color=white>Вы записались на ивент, чтобы быть Джаггернаутом.Вы можете выйти в любое время, набрав </color><color=#ffd479>/jug leave</color>", player.UserIDString));
PrintToChat(string.Format(msg("<color=#ffd479>{0}</color> <color=white>зарегистрировался на ивент Джаггернаут!</color> <color=#ffd479>({1} игроков зарегестрировано)</color>"), player.displayName, optedIn.Count));
}
return;
case "leave" : if (!isOpen) {
SendReply(player, msg("<color=white>На данный момент нет открытого ивента</color>", player.UserIDString));
return;
}
if (optedIn.Contains(player.userID)) optedIn.Remove(player.userID);
SendReply(player, msg("<color=white>Вы удалили себя из жеребьёвки, чтобы стать Джаггернаутом</color>", player.UserIDString));
return;
case "claim" : if (storedData.winnerRewards.ContainsKey(player.userID)) {
foreach(var prize in storedData.winnerRewards[player.userID]) {
Item item = ItemManager.CreateByItemID(prize.itemid, prize.amount, prize.skin);
item.condition = prize.condition;
if (prize.instanceData != null) item.instanceData = prize.instanceData;
var weapon = item.GetHeldEntity() as BaseProjectile;
if (weapon != null) {
if (!string.IsNullOrEmpty(prize.ammotype)) weapon.primaryMagazine.ammoType = ItemManager.FindItemDefinition(prize.ammotype);
weapon.primaryMagazine.contents = prize.ammo;
}
if (prize.contents != null) {
foreach (var contentData in prize.contents) {
var newContent = ItemManager.CreateByItemID(contentData.itemid, contentData.amount);
if (newContent != null) {
newContent.condition = contentData.condition;
newContent.MoveToContainer(item.contents);
}
}
}
player.GiveItem(item, BaseEntity.GiveItemReason.Generic);
}
SendReply(player, msg("<color=white>Вы выиграли приз</color>", player.UserIDString));
storedData.winnerRewards.Remove(player.userID);
SaveData();
}
else if (storedData.winnerMoney.ContainsKey(player.userID)) {
foreach(var prize in storedData.winnerMoney[player.userID]) {
if (prize.isRp) ServerRewards?.Call("AddPoints", player.userID, prize.amount);
else Economics?.Call("Deposit", player.userID, (double)prize.amount);
}
SendReply(player, msg("<color=white>Вы выиграли приз</color>", player.UserIDString));
storedData.winnerMoney.Remove(player.userID);
SaveData();
}
else SendReply(player, msg("<color=white>У вас нет призов</color>", player.UserIDString));
return;
case "restore" : if (player == juggernaut) {
SendReply(player, msg("<color=white>Вы не можете восстановиться, будучи Джаггернаутом</color>", player.UserIDString));
return;
}
if (storedData.unrestoredPlayers.ContainsKey(player.userID)) {
TryRestorePlayer(player);
return;
}
else SendReply(player, msg("<color=white>У вас нет сохраненных данных восстановления</color>", player.UserIDString));
return;
case "open" : if (player.IsAdmin) {
if (isOpen) {
SendReply(player, msg("<color=white>Ивент уже открыт</color>", player.UserIDString));
return;
}
if (!hasDestinations) {
SendReply(player, msg("<color=white>Не настроены адресаты! Не удалось начать ивент</color>", player.UserIDString));
return;
}
if (hasStarted) {
SendReply(player, msg("<color=white>Ивент уже начался</color>", player.UserIDString));
return;
}
if (nextMatch != null) nextMatch.Destroy();
OpenEvent();
}
return;
case "start" : if (player.IsAdmin) {
if (!isOpen) {
SendReply(player, msg("isntOpen", player.UserIDString));
return;
}
if (hasStarted) {
SendReply(player, msg("<color=white>Ивент уже начался</color>", player.UserIDString));
return;
}
if (startMatch != null) startMatch.Destroy();
if (openMessage != null) openMessage.Destroy();
StartEvent();
}
return;
case "cancel" : if (player.IsAdmin) {
if (!isOpen && !hasStarted) {
SendReply(player, msg("notStarted", player.UserIDString));
return;
}
if (isOpen) {
if (startMatch != null) startMatch.Destroy();
if (openMessage != null) openMessage.Destroy();
isOpen = false;
PrintToChat(msg("<color=orange>[Джаггернаут]</color><color=white> : Админ отменил ивент!</color>"));
StartEventTimer();
return;
}
if (hasStarted) {
PrintToChat(msg("<color=orange>[Джаггернаут]</color><color=white> : Админ отменил ивент!</color>"));
// ... [Code preview truncated due to length. Full source in attached file] ...