From 71db52c5443a7bf82d9a23a770994a42b043be04 Mon Sep 17 00:00:00 2001 From: Leonardo Bishop Date: Thu, 27 Jul 2023 22:11:31 +0100 Subject: Initial commit --- code/phase/AssignPhase.cs | 89 +++++++++++++++++++++++++++++++ code/phase/BasePhase.cs | 28 ++++++++++ code/phase/EndPhase.cs | 26 +++++++++ code/phase/PlayPhase.cs | 133 ++++++++++++++++++++++++++++++++++++++++++++++ code/phase/WaitPhase.cs | 43 +++++++++++++++ 5 files changed, 319 insertions(+) create mode 100644 code/phase/AssignPhase.cs create mode 100644 code/phase/BasePhase.cs create mode 100644 code/phase/EndPhase.cs create mode 100644 code/phase/PlayPhase.cs create mode 100644 code/phase/WaitPhase.cs (limited to 'code/phase') diff --git a/code/phase/AssignPhase.cs b/code/phase/AssignPhase.cs new file mode 100644 index 0000000..26c9fc1 --- /dev/null +++ b/code/phase/AssignPhase.cs @@ -0,0 +1,89 @@ +using Sandbox; +using Sandbox.UI; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MurderGame; + +public class AssignPhase : BasePhase +{ + public override string Title => "Assigning teams"; + public int TicksElapsed; + + public override void Activate() + { + foreach (var entity in Entity.All.OfType()) + { + entity.Delete(); + } + + var detectivesNeeded = 1; + var murderersNeeded = 1; + + List spawnpoints = Entity.All.OfType().OrderBy( x => Guid.NewGuid() ).ToList(); + var clients = Game.Clients.ToList(); + foreach ( int i in Enumerable.Range( 0, clients.Count ).OrderBy( x => Guid.NewGuid() ) ) + { + var client = clients[i]; + if (client.Pawn != null) + { + ((Player) client.Pawn).Cleanup(); + client.Pawn.Delete(); + } + Player pawn = new(); + client.Pawn = pawn; + if (spawnpoints.Count == 0) + { + ChatBox.Say( "Could not spawn " + client.Name + " as there are not enough spawn points." ); + pawn.CurrentTeam = Team.Spectator; + continue; + } + pawn.DressFromClient( client ); + + if (murderersNeeded > 0) + { + pawn.CurrentTeam = Team.Murderer; + --murderersNeeded; + } + else if (detectivesNeeded > 0) + { + pawn.CurrentTeam = Team.Detective; + --detectivesNeeded; + } + else + { + pawn.CurrentTeam = Team.Bystander; + } + Log.Info( "Assigning " + client.Name + " to team " + TeamOperations.GetTeamName( pawn.CurrentTeam ) ); + + var spawnpoint = spawnpoints[0]; + spawnpoints.RemoveAt( 0 ); + var tx = spawnpoint.Transform; + tx.Position = tx.Position + Vector3.Up * 50.0f; + pawn.Transform = tx; + + RoleOverlay.Show( To.Single( client ) ); + } + base.TimeLeft = 5; + } + + public override void Deactivate() + { + foreach (var client in Game.Clients) + { + RoleOverlay.Hide( To.Single( client ) ); + } + } + + public override void Tick() + { + ++TicksElapsed; + if ( base.TimeLeft != -1 && TicksElapsed % Game.TickRate == 0 && --base.TimeLeft == 0 ) + { + base.IsFinished = true; + base.NextPhase = new PlayPhase(); + } + } + +} diff --git a/code/phase/BasePhase.cs b/code/phase/BasePhase.cs new file mode 100644 index 0000000..8f3d044 --- /dev/null +++ b/code/phase/BasePhase.cs @@ -0,0 +1,28 @@ +using Sandbox; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MurderGame; + +public abstract partial class BasePhase : BaseNetworkable +{ + public virtual string Title => "Name"; + + [Net] + public int TimeLeft { get; set; } = -1; + + public BasePhase NextPhase { get; set;} + + public bool IsFinished { get; set; } + + public abstract void Tick(); + + public virtual void Activate() { } + + public virtual void Deactivate() { } + + public virtual void HandleClientJoin(ClientJoinedEvent e) { } +} diff --git a/code/phase/EndPhase.cs b/code/phase/EndPhase.cs new file mode 100644 index 0000000..904dc81 --- /dev/null +++ b/code/phase/EndPhase.cs @@ -0,0 +1,26 @@ +using Sandbox; +using System.Linq; + +namespace MurderGame; + +public class EndPhase : BasePhase +{ + public override string Title => "Game over"; + public int TicksElapsed; + + public override void Activate() + { + base.TimeLeft = 7; + } + + public override void Tick() + { + ++TicksElapsed; + if (base.TimeLeft != -1 && TicksElapsed % Game.TickRate == 0 && --base.TimeLeft == 0) + { + base.NextPhase = new WaitPhase() { CountIn = false }; + base.IsFinished = true; + return; + } + } +} diff --git a/code/phase/PlayPhase.cs b/code/phase/PlayPhase.cs new file mode 100644 index 0000000..118529e --- /dev/null +++ b/code/phase/PlayPhase.cs @@ -0,0 +1,133 @@ +using Sandbox; +using Sandbox.UI; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Linq; + +namespace MurderGame; + +public class PlayPhase : BasePhase +{ + public override string Title => "Play"; + public IDictionary Blinded = new Dictionary(); + public int TicksElapsed; + private string MurdererNames { get; set; } + + public override void Activate() + { + base.TimeLeft = MurderGame.RoundTime; + Event.Register(this); + foreach ( var client in Game.Clients ) + { + if ( client.Pawn is Player pawn ) + { + if (pawn.CurrentTeam != Team.Spectator) + { + pawn.Respawn(); + TeamOperations.GiveLoadouts( pawn ); + } + } + } + MurdererNames = string.Join( ',', Game.Clients.Where( c => ((Player)c.Pawn).CurrentTeam == Team.Murderer ).Select(c => c.Name)); + } + + public override void Deactivate() + { + base.TimeLeft = MurderGame.RoundTime; + Event.Unregister(this); + foreach(var item in Blinded) + { + ClearDebuffs( item.Key ); + } + Blinded.Clear(); + } + + public void ClearDebuffs(Entity entity ) + { + Log.Info( "Removing blind from " + entity.Name ); + BlindedOverlay.Hide( To.Single( entity ) ); + if (entity is Player pawn && pawn.IsValid() ) + { + if (pawn.Controller != null) pawn.Controller.SpeedMultiplier = 1; + if (pawn.Inventory != null) pawn.Inventory.AllowPickup = true; + } + + } + + public override void Tick() + { + ++TicksElapsed; + if (base.TimeLeft != -1 && TicksElapsed % Game.TickRate == 0 && --base.TimeLeft == 0) + { + TriggerEndOfGame(); + return; + } + bool bystandersAlive = Game.Clients.Any(c =>((Player)c.Pawn).CurrentTeam == Team.Bystander || ((Player)c.Pawn).CurrentTeam == Team.Detective); + bool murderersAlive = Game.Clients.Any(c =>((Player)c.Pawn).CurrentTeam == Team.Murderer); + if (!bystandersAlive || !murderersAlive) + { + TriggerEndOfGame(); + } + + foreach(var item in Blinded) + { + var blindLeft = item.Value - 1; + if (blindLeft < 0) + { + Blinded.Remove( item.Key ); + ClearDebuffs( item.Key ); + Log.Info( "Removing blind from " + item.Key.Name ); + } + else + { + Blinded[item.Key] = blindLeft; + } + } + } + + public void TriggerEndOfGame() + { + bool bystandersWin = Game.Clients.Any(c =>((Player)c.Pawn).CurrentTeam == Team.Bystander || ((Player)c.Pawn).CurrentTeam == Team.Detective); + ChatBox.Say( (bystandersWin ? "Bystanders" : "Murderers") +" win! The murderers were: " + MurdererNames ); + base.NextPhase = new EndPhase(); + base.IsFinished = true; + } + + [MurderEvent.Kill] + public void OnKill(Entity killer, Entity victim) + { + if (killer == null || killer is not Player || victim == null || victim is not Player ) + { + return; + } + Player victimPlayer = (Player)victim; + Player killerPlayer = (Player)killer; + Team victimTeam = victimPlayer.CurrentTeam; + Team killerTeam = killerPlayer.CurrentTeam; + victimPlayer.CurrentTeam = Team.Spectator; + + Log.Info( victimPlayer + " died to " + killerPlayer ); + if (victimTeam != Team.Murderer && killerTeam != Team.Murderer) + { + Log.Info( killerPlayer + " shot a bystander"); + ChatBox.Say( killerPlayer.Client.Name + " killed an innocent bystander" ); + BlindedOverlay.Show( To.Single( killer ) ); + if (killerPlayer.Controller != null) killerPlayer.Controller.SpeedMultiplier = 0.3f; + if (killerPlayer.Inventory != null) + { + Log.Info( killerPlayer + "bonk"); + killerPlayer.Inventory.AllowPickup = false; + killerPlayer.Inventory.SpillContents(killerPlayer.EyePosition, killerPlayer.AimRay.Forward); + } + + Blinded[killer] = 20 * Game.TickRate; + } + else if (victimTeam == Team.Murderer ) + { + Log.Info( killerPlayer + " killed a murderer"); + ChatBox.Say( killerPlayer.Client.Name + " killed a murderer" ); + } + } + +} diff --git a/code/phase/WaitPhase.cs b/code/phase/WaitPhase.cs new file mode 100644 index 0000000..4f2e876 --- /dev/null +++ b/code/phase/WaitPhase.cs @@ -0,0 +1,43 @@ +using Sandbox; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MurderGame; + +public class WaitPhase : BasePhase +{ + public override string Title => "Waiting for players"; + public bool CountIn { get; set; } + public int TicksElapsed { get; set; } + + private bool _isCountDown { get; set; } + + public override void Tick() + { + if (Game.Clients.Count >= MurderGame.MinPlayers) + { + if (!CountIn || (_isCountDown && ++TicksElapsed % Game.TickRate == 0 && --base.TimeLeft == 0)) + { + base.NextPhase = new AssignPhase(); + base.IsFinished = true; + } + else if (CountIn && !_isCountDown) + { + _isCountDown = true; + base.TimeLeft = 10; + } + } else if (CountIn && _isCountDown) + { + _isCountDown = false; + base.TimeLeft = -1; + } + } + + public override void HandleClientJoin( ClientJoinedEvent e ) + { + + } +} -- cgit v1.2.3-70-g09d2