Skip to content

Commit

Permalink
Dev to main (#15)
Browse files Browse the repository at this point in the history
* Effect rework

* The funny

* Fixed some stuff, added new configs for Arena mode

* Added Arena.List.Clear() at the WaitingForPlayers

* Fixed spectator bug, added support for multiple arena spawnpoints

* Added lobby checks

* Fixed MER

* Global voice chat and static spawn points

* Implemented an experimental method of moving player on spawn

* Removed global voice chat

* Pause FFD during lobby (#14)

* Bump

Co-authored-by: Thunder <[email protected]>
  • Loading branch information
Michal78900 and Thunder authored Jun 16, 2022
1 parent bb04903 commit 9d5bbd6
Show file tree
Hide file tree
Showing 18 changed files with 1,035 additions and 595 deletions.
22 changes: 22 additions & 0 deletions WaitAndChillReborn/API/API.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace WaitAndChillReborn.API
{
using Exiled.API.Features;
using MEC;
using System.Collections.Generic;
using UnityEngine;

public static class API
{
public static Vector3 LobbyChoosedSpawnPoint;

public static List<Vector3> LobbyAvailableSpawnPoints = new List<Vector3>();

public static CoroutineHandle LobbyTimer;

public static bool IsLobby => !Round.IsStarted && !RoundSummary.singleton.RoundEnded;

public static bool MapEditorRebornInstalled { get; internal set; }

public const string AtachedArenaSessionVarName = "WACR_AttachedArena";
}
}
83 changes: 83 additions & 0 deletions WaitAndChillReborn/API/Features/Arena.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
namespace WaitAndChillReborn.API.Features
{
using Exiled.API.Features;
using MapEditorReborn.API.Features;
using MapEditorReborn.API.Features.Objects;
using Mirror;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Configs;
using System;

using Random = UnityEngine.Random;

public unsafe class Arena
{
public static Vector3 NextArenaSpawnPosition = new Vector3(1000f, 1000f, 0f);

public static List<Arena> List = new List<Arena>();

public static Arena Create(SchematicObject schematic) => new Arena(schematic);

public static Arena GetEmptyArena()
{
Arena arena = List.FirstOrDefault(x => x.IsAvailable);
return arena ?? Create(ObjectSpawner.SpawnSchematic(GetRandomArenaName(), NextArenaSpawnPosition));
}

private Arena(SchematicObject schematic)
{
List<Vector3> ntfList = NorthwoodLib.Pools.ListPool<Vector3>.Shared.Rent();
List<Vector3> ciList = NorthwoodLib.Pools.ListPool<Vector3>.Shared.Rent();

foreach (GameObject block in schematic.AttachedBlocks.ToList())
{
if (block.name.Contains(NtfSpawnPointName))
{
ntfList.Add(block.transform.position);
schematic.AttachedBlocks.Remove(block);
NetworkServer.Destroy(block);
}
else if (block.name.Contains(CiSpawnPointName))
{
ciList.Add(block.transform.position);
schematic.AttachedBlocks.Remove(block);
NetworkServer.Destroy(block);
}
}

if (ntfList.Count == 0 || ciList.Count == 0)
{
Log.Error($"One or more of the spawnpoints in \"{schematic.Name}\" arena are missing.");
return;
}

Schematic = schematic;
NtfSpawnPoints = ntfList.AsReadOnly();
CiSpawnPoints = ciList.AsReadOnly();
NextArenaSpawnPosition += Vector3.back * Config.DistanceBetweenArenas;

IsAvailable = true;
List.Add(this);

NorthwoodLib.Pools.ListPool<Vector3>.Shared.Return(ntfList);
NorthwoodLib.Pools.ListPool<Vector3>.Shared.Return(ciList);
}

public SchematicObject Schematic { get; }

public IReadOnlyList<Vector3> NtfSpawnPoints { get; }

public IReadOnlyList<Vector3> CiSpawnPoints { get; }

public bool IsAvailable { get; set; }

private static string GetRandomArenaName() => Config.ArenaNames[Random.Range(0, Config.ArenaNames.Count)];

private const string NtfSpawnPointName = "NTF_SPAWN";
private const string CiSpawnPointName = "CI_SPAWN";

private static readonly ArenaConfig Config = WaitAndChillReborn.Singleton.Config.ArenaConfig;
}
}
201 changes: 201 additions & 0 deletions WaitAndChillReborn/ArenaHandlers/ArenaEventHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
namespace WaitAndChillReborn.Handlers
{
using Exiled.API.Features.Items;
using Exiled.Events.EventArgs;
using API.Features;
using MEC;
using System.Linq;
using Exiled.API.Extensions;
using Methods;
using UnityEngine;
using Exiled.API.Features;
using Configs;
using GameCore;

using static API.API;

using PlayerEvent = Exiled.Events.Handlers.Player;
using ServerEvent = Exiled.Events.Handlers.Server;

internal static class ArenaEventHandler
{
internal static void RegisterEvents()
{
ServerEvent.WaitingForPlayers += OnWaitingForPlayers;
PlayerEvent.Verified += OnVerified;

PlayerEvent.Spawning += OnSpawning;
MapEditorReborn.Events.Handlers.Schematic.ButtonInteracted += OnButtonInteracted;

PlayerEvent.ReloadingWeapon += OnReloading;
PlayerEvent.Dying += OnDying;

PlayerEvent.SpawningRagdoll += OnSpawningRagdoll;
PlayerEvent.DroppingItem += OnDroppingItem;
PlayerEvent.DroppingAmmo += OnDroppingAmmo;

ServerEvent.RoundStarted += OnRoundStarted;
}

internal static void UnRegisterEvents()
{
ServerEvent.WaitingForPlayers -= OnWaitingForPlayers;
PlayerEvent.Verified -= OnVerified;

PlayerEvent.Spawning -= OnSpawning;
MapEditorReborn.Events.Handlers.Schematic.ButtonInteracted += OnButtonInteracted;

PlayerEvent.ReloadingWeapon -= OnReloading;
PlayerEvent.Dying -= OnDying;

PlayerEvent.SpawningRagdoll -= OnSpawningRagdoll;
PlayerEvent.DroppingItem -= OnDroppingItem;
PlayerEvent.DroppingAmmo -= OnDroppingAmmo;

ServerEvent.RoundStarted -= OnRoundStarted;
}

private static void OnWaitingForPlayers()
{
GameObject.Find("StartRound").transform.localScale = Vector3.zero;

if (LobbyTimer.IsRunning)
{
Timing.KillCoroutines(LobbyTimer);
}

if (WaitAndChillReborn.Singleton.Config.DisplayWaitMessage)
LobbyTimer = Timing.RunCoroutine(LobbyMethods.LobbyTimer());

Arena.List.Clear();
ArenaClock = Timing.RunCoroutine(ArenaMethods.ArenaClock());
}

private static void OnVerified(VerifiedEventArgs ev)
{
// if (IsLobby && !WaitAndChillReborn.Singleton.Config.GlobalVoiceChat)
// ev.Player.SendFakeSyncVar(RoundStart.singleton.netIdentity, typeof(RoundStart), nameof(RoundStart.NetworkTimer), (short)-1);
}

private static void OnSpawning(SpawningEventArgs ev)
{
if (!IsLobby)
return;

if (ev.Player.TryGetSessionVariable(AtachedArenaSessionVarName, out Arena arena))
ev.Position = ev.RoleType == RoleType.NtfCaptain ? arena.NtfSpawnPoints[Random.Range(0, arena.NtfSpawnPoints.Count)] : arena.CiSpawnPoints[Random.Range(0, arena.CiSpawnPoints.Count)];

ev.Player.ClearInventory();
ev.Player.AddItem(ItemType.ArmorHeavy);

ev.Player.Ammo.Clear();
ev.Player.Ammo.Add(ItemType.Ammo556x45, 1);
ev.Player.Ammo.Add(ItemType.Ammo762x39, 1);
ev.Player.Ammo.Add(ItemType.Ammo9x19, 1);
ev.Player.Ammo.Add(ItemType.Ammo44cal, 1);
ev.Player.Ammo.Add(ItemType.Ammo12gauge, 1);
}

private static void OnButtonInteracted(MapEditorReborn.Events.EventArgs.ButtonInteractedEventArgs ev)
{
if (!IsLobby)
return;

if (!Config.ArenaNames.Contains(ev.Schematic.Name))
return;

Item weapon = ev.Player.Items.FirstOrDefault(x => x.IsWeapon);
if (weapon != null)
ev.Player.RemoveItem(weapon);

Item item = ev.Player.AddItem(ev.Button.Type);
ev.Player.CurrentItem = item;
}

private static void OnReloading(ReloadingWeaponEventArgs ev)
{
if (!IsLobby)
return;

ushort num = (ushort)(ev.Firearm.MaxAmmo - ev.Firearm.Ammo - ev.Player.Ammo[ev.Firearm.AmmoType.GetItemType()] + 1);

if (num == 0)
return;

ev.Player.AddAmmo(ev.Firearm.AmmoType, num);
}

private static void OnDying(DyingEventArgs ev)
{
if (!IsLobby)
return;

if (ev.Killer == null)
return;

ev.Target.ClearInventory();
ev.Target.Ammo.Clear();

Timing.CallDelayed(Config.RespawnTime, () =>
{
if (!IsLobby)
return;
ev.Killer.ClearInventory();
ev.Killer.Ammo.Clear();
ev.Killer.Role.Type = RoleType.Spectator;
if (ev.Killer.TryGetSessionVariable(AtachedArenaSessionVarName, out Arena arena))
arena.IsAvailable = true;
});
}
private static void OnSpawningRagdoll(SpawningRagdollEventArgs ev)
{
if (IsLobby)
{
ev.IsAllowed = false;
Ragdoll ragdoll = new Ragdoll(ev.Info, true);

Timing.CallDelayed(Config.RespawnTime, () => ragdoll.Delete());
}
}

private static void OnDroppingItem(DroppingItemEventArgs ev)
{
if (IsLobby)
{
ev.IsAllowed = false;
}
}

private static void OnDroppingAmmo(DroppingAmmoEventArgs ev)
{
if (IsLobby)
{
ev.IsAllowed = false;
}
}

private static void OnRoundStarted()
{
Timing.KillCoroutines(ArenaClock);

foreach (Player player in Player.List)
{
player.ClearInventory();
player.Role.Type = RoleType.Spectator;
}

foreach (Arena arena in Arena.List)
{
arena.Schematic.Destroy();
}
Arena.List.Clear();
}

private static CoroutineHandle ArenaClock;

private static readonly ArenaConfig Config = WaitAndChillReborn.Singleton.Config.ArenaConfig;
}
}
83 changes: 83 additions & 0 deletions WaitAndChillReborn/ArenaHandlers/ArenaMethods.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
namespace WaitAndChillReborn.Methods
{
using Exiled.API.Features;
using MEC;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using API.Features;
using Configs;

using static API.API;

internal static class ArenaMethods
{
internal static IEnumerator<float> ArenaClock()
{
while (true)
{
yield return Timing.WaitForSeconds(Config.ClockUpdateTime);
try
{
Player ntf;
Player ci;
List<Player> availablePlayers = Player.Get(Team.RIP).ToList();

if (availablePlayers.Count < 2)
continue;

ntf = availablePlayers[Random.Range(0, availablePlayers.Count)];
availablePlayers.Remove(ntf);

if (availablePlayers.Count < 1)
continue;

ci = availablePlayers[Random.Range(0, availablePlayers.Count)];

Arena arena = Arena.GetEmptyArena();
arena.IsAvailable = false;

if (!ntf.SessionVariables.ContainsKey(AtachedArenaSessionVarName))
ntf.SessionVariables.Add(AtachedArenaSessionVarName, null);

if (!ci.SessionVariables.ContainsKey(AtachedArenaSessionVarName))
ci.SessionVariables.Add(AtachedArenaSessionVarName, null);

ntf.SessionVariables[AtachedArenaSessionVarName] = arena;
ci.SessionVariables[AtachedArenaSessionVarName] = arena;

SetupPlayer(ntf, RoleType.NtfCaptain);
SetupPlayer(ci, RoleType.ChaosMarauder);
}
catch (System.Exception e)
{
Log.Error(e);
}
}

}

internal static void SetupPlayer(Player player, RoleType roleType)
{
Timing.CallDelayed(0.25f, () =>
{
if (IsLobby)
player.Role.Type = roleType;
});

Timing.CallDelayed(0.3f, () =>
{
if (IsLobby)
player.ClearInventory();
});

Timing.CallDelayed(0.5f, () =>
{
if (IsLobby)
player.AddItem(ItemType.ArmorHeavy);
});
}

private static readonly ArenaConfig Config = WaitAndChillReborn.Singleton.Config.ArenaConfig;
}
}
Loading

0 comments on commit 9d5bbd6

Please sign in to comment.