Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions SillySCP/API/Extensions/InventoryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using InventorySystem.Items.Pickups;
using LabApi.Features.Wrappers;
using Mirror;
using PlayerRoles;
using SecretAPI.Extensions;
using UnityEngine;
using Logger = LabApi.Features.Console.Logger;

namespace SillySCP.API.Extensions;

public static class InventoryExtensions

{
public static void FreezeItemPickup(ItemPickupBase pickup)
{
Logger.Info($"Freezing item pickup {pickup.name}");
pickup.Info.Locked = true;
pickup.Info.InUse = true;

PickupStandardPhysics physics = pickup.PhysicsModule as PickupStandardPhysics;

physics!.Rb.constraints = RigidbodyConstraints.FreezeAll;
physics!.Rb.isKinematic = true;
if (pickup is InventorySystem.Items.ThrowableProjectiles.Scp018Projectile projectile) projectile.TargetTime = NetworkTime.time + 60 * 60;
}
public static List<Pickup> CloneItems(this Player player)
{
List<Pickup> pickups = new ();
foreach (var item in player.Items)
{

ItemPickupBase ipb = UnityEngine.Object.Instantiate(item.Base.PickupDropModel, Vector3.up, Quaternion.identity);
ipb.NetworkInfo = new PickupSyncInfo(item.Base.ItemTypeId,item.Base.Weight,item.Base.ItemSerial,locked:true);
FreezeItemPickup(ipb);
Pickup pickup = Pickup.Get(ipb);

pickups.Add(pickup);
}
return pickups;
}
}
111 changes: 111 additions & 0 deletions SillySCP/API/Features/TowerSitSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using CustomPlayerEffects;
using InventorySystem.Items.Usables.Scp1344;
using LabApi.Features.Wrappers;
using NorthwoodLib.Pools;
using PlayerRoles;
using PlayerRoles.PlayableScps.Scp079;
using SillySCP.API.Extensions;
using UnityEngine;
using Scp1344Item = LabApi.Features.Wrappers.Scp1344Item;

namespace SillySCP.API.Features;

public sealed class SitInfo // if need be this could be repurposed into a way to Stash a players state
{
public readonly Player Player;
public readonly PlayerRoleBase Role;

public readonly List<(StatusEffectBase Effect,float RemainingDuration,byte Intensity)> ActiveEffects = [];
public readonly List<Pickup> Inventory;
public readonly KeyValuePair<ItemType,ushort>[] Ammo;

public readonly float MaxHealth;
public readonly float Health;

public readonly float MaxHume;
public readonly float Hume;

public readonly Vector3 Position;

public readonly int ComputerXp;
public SitInfo(Player player)
{
Player = player;
Role = player.RoleBase;

foreach (var effect in player.ActiveEffects) ActiveEffects.Add((effect,effect.TimeLeft,effect.Intensity));

Inventory = player.CloneItems();
Ammo = player.Ammo.ToArray();

MaxHealth = player.MaxHealth;
Health = player.Health;

MaxHume = player.MaxHumeShield;
Hume = player.HumeShield;

Position = player.Position;
if (Player.RoleBase is Scp079Role computerRole)
{
computerRole.SubroutineModule.TryGetSubroutine(out Scp079TierManager tierManager);
ComputerXp = tierManager.TotalExp ;
}
}

public void RestorePlayer()
{
if (!Player.IsOnline) return; // just in case they disconnect and something tries to restore them
Player.SetRole(Role.RoleTypeId,reason:RoleChangeReason.RemoteAdmin, flags:RoleSpawnFlags.None);

foreach (var effect in ActiveEffects) Player.EnableEffect(effect.Effect,effect.Intensity,effect.RemainingDuration);

foreach (Pickup pickup in Inventory)
{
Item item = Player.AddItem(pickup);

if (ActiveEffects.Exists(activeEffect => activeEffect.Effect is Scp1344))
if (item is Scp1344Item scp1344) {
Player.DisableEffect<Scp1344>();
scp1344.Use(); //any effect that puts something on the players screen doesn't like being set frame 0
scp1344.Status = Scp1344Status.Active;
}
}
ListPool<Pickup>.Shared.Return(Inventory);

foreach (KeyValuePair<ItemType, ushort> ammo in Ammo) Player.AddAmmo(ammo.Key,ammo.Value);

Player.MaxHealth = MaxHealth;
Player.Health = Health;

Player.MaxHumeShield = MaxHume;
Player.HumeShield = Hume;

Player.Position = Position;
if (Player.RoleBase is Scp079Role computerRole)
{
computerRole.SubroutineModule.TryGetSubroutine(out Scp079TierManager tierManager);
tierManager.TotalExp = ComputerXp;
}
}
}

public static class TowerSitSystem
{
public static Dictionary<Player,SitInfo> ActiveSits = new ();

public static void Start(Player player)
{
if (ActiveSits.ContainsKey(player)) return;
SitInfo sit = new(player);
ActiveSits[player] = sit;

player.SetRole(RoleTypeId.Tutorial);
}

public static void End(Player player)
{
if (!ActiveSits.TryGetValue(player, out SitInfo sit)) return;
sit.RestorePlayer();
ActiveSits.Remove(player);
}
}
56 changes: 15 additions & 41 deletions SillySCP/Commands/TowerSit.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using CommandSystem;
using LabApi.Features.Stores;
using LabApi.Features.Wrappers;
using PlayerRoles;
using SecretAPI.Extensions;
using SillySCP.API.Features;
using UnityEngine;


namespace SillySCP.Commands
{
public class DataStore : CustomDataStore
Expand All @@ -19,87 +19,61 @@ public DataStore(Player player)
[CommandHandler(typeof(RemoteAdminCommandHandler))]
public class TowerSit : ICommand
{
private void AddPlayer(Player player)
{
player.GetDataStore<DataStore>().Position = player.Position;
player.IsGodModeEnabled = true;
if (player.IsSCP)
{
player.SendBroadcast("If you go to Settings, Server-specific, you can set a bind for proximity chat",10);
}
RoleTypeId.Tutorial.GetRandomSpawnPosition(out Vector3 position, out float _);
player.Position = position;
}
private static bool RestorePlayer(Player player)
{
DataStore store = player.GetDataStore<DataStore>();
player.Position = (Vector3)store.Position!;
store.Position = null;
player.IsGodModeEnabled = false;
return true;
}


public string Command { get; } = "towersit";
public string Description { get; } = "Teleport a player to the tower and return them after";
public string[] Aliases { get; } = ["ts"];

private const string Usage = "Invalid Usage, Applicable usages:" +
"\n ts add <PLAYER> - teleport a player to the tower (Both IDs and Partial Usernames are accepted)" +
"\n ts restore <PLAYER> - restore a players original position (Both IDs and Partial Usernames are accepted)";
"\n ts add <PLAYER> - Create a towersit (Usernames are accepted)" +
"\n ts restore <PLAYER> - End a towersit (Usernames are accepted)";

public bool Execute(
ArraySegment<string> arguments,
ICommandSender sender,
out string response
)
{

if (arguments.Count != 2)
{
response = Usage;
return false;
}

if (!Player.TryGet(arguments.At(1), out Player player))
if (!Player.TryGetPlayersByName(arguments.At(1), out List<Player> players)) // no method for the first player to match
{
response = "Must be a player!";
return false;
}

if (!player.IsAlive)
{
response = "Player is dead!";
return false;
}
Player player = players.First();

switch (arguments.At(0))
{
case "add":
if (player.GetDataStore<DataStore>().Position != null)
if (TowerSitSystem.ActiveSits.ContainsKey(player))
{
response = "Player already has a return position!";
response =$"{player.Nickname} is already in the tower!";
return false;
}
AddPlayer(player);
response = $"{player.Nickname} teleporting to the tower!";
TowerSitSystem.Start(player);
response = $"{player.Nickname} has been towered!";
return true;

case "restore":
if (!RestorePlayer(player))
if (!TowerSitSystem.ActiveSits.ContainsKey(player))
{
response = $"Player {player.Nickname} doesnt have a return position!";
response = $"Player {player.Nickname} is not actively in the tower!";
return false;
}
response = $"{player.Nickname} restored from the tower!";

TowerSitSystem.End(player);
response = $"returned {player.Nickname} from the tower!";
return true;

default:
response = Usage;
return false;

}

}
}
}
17 changes: 17 additions & 0 deletions SillySCP/Patches/DropAllAmmoPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using HarmonyLib;
using NorthwoodLib.Pools;

namespace SillySCP.Patches;
[HarmonyPatch(typeof(LabApi.Features.Wrappers.Player), nameof(LabApi.Features.Wrappers.Player.DropAllAmmo))]
public class DropAllAmmoPatch
{
public static bool Prefix(LabApi.Features.Wrappers.Player __instance, ref List<LabApi.Features.Wrappers.AmmoPickup> __result)
{
List<LabApi.Features.Wrappers.AmmoPickup> ammo = ListPool<LabApi.Features.Wrappers.AmmoPickup>.Shared.Rent();
foreach (KeyValuePair<ItemType, ushort> pair in __instance.Ammo.ToDictionary(e => e.Key, e => e.Value))
ammo.AddRange(__instance.DropAmmo(pair.Key, pair.Value));

__result = ammo;
return false;
}
}
Loading