-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 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
1 parent
bb04903
commit 9d5bbd6
Showing
18 changed files
with
1,035 additions
and
595 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
Oops, something went wrong.