From dbf0218371ce006b674b0ede8e6a4d97932ff2c6 Mon Sep 17 00:00:00 2001 From: Leonardo Bishop Date: Tue, 1 Aug 2023 01:31:25 +0100 Subject: Add footprints --- code/Game.cs | 9 ++-- code/entity/Footprint.cs | 55 +++++++++++++++++++++++ code/pawn/Player.Character.cs | 11 ++++- code/pawn/Player.cs | 2 + code/pawn/component/FootprintTrackerComponent.cs | 51 +++++++++++++++++++++ code/phase/AssignPhase.cs | 49 +++++++++++--------- code/team/Team.cs | 1 + materials/left_shoe_footprint.png | Bin 0 -> 6424 bytes materials/left_shoe_footprint.vmat | 49 ++++++++++++++++++++ materials/right_shoe_footprint.png | Bin 0 -> 6696 bytes materials/right_shoe_footprint.vmat | 49 ++++++++++++++++++++ 11 files changed, 251 insertions(+), 25 deletions(-) create mode 100644 code/entity/Footprint.cs create mode 100644 code/pawn/component/FootprintTrackerComponent.cs create mode 100644 materials/left_shoe_footprint.png create mode 100644 materials/left_shoe_footprint.vmat create mode 100644 materials/right_shoe_footprint.png create mode 100644 materials/right_shoe_footprint.vmat diff --git a/code/Game.cs b/code/Game.cs index ad04fc8..356cd38 100644 --- a/code/Game.cs +++ b/code/Game.cs @@ -23,14 +23,17 @@ public partial class MurderGame : Sandbox.GameManager } - [ConVar.Server( "mm_min_players", Help = "The minimum number of players required to start a round." )] + [ConVar.Server( "mu_min_players", Help = "The minimum number of players required to start a round." )] public static int MinPlayers { get; set; } = 2; - [ConVar.Server( "mm_allow_suicide", Help = "Allow players to kill themselves during a round." )] + [ConVar.Server( "mu_allow_suicide", Help = "[INOP] Allow players to kill themselves during a round." )] public static bool AllowSuicide { get; set; } = true; - [ConVar.Server( "mm_round_time", Help = "The amount of time in a round." )] + [ConVar.Server( "mu_round_time", Help = "The amount of time, in seconds, in a round." )] public static int RoundTime { get; set; } = 600; + + [ConVar.Client( "mu_max_footprint_time", Help = "The amount of time, in seconds, footprints are visible for. Max 30 seconds." )] + public static int MaxFootprintTime { get; set; } = 30; [Net] public BasePhase CurrentPhase { get; set; } = new WaitPhase() { CountIn = true }; diff --git a/code/entity/Footprint.cs b/code/entity/Footprint.cs new file mode 100644 index 0000000..8941e95 --- /dev/null +++ b/code/entity/Footprint.cs @@ -0,0 +1,55 @@ +using System; + +namespace MurderGame; + +using Sandbox; +// It's just a square with a material slapped onto it. +public class Footprint : RenderEntity +{ + public Material SpriteMaterial { get; set; } + + public float SpriteScale { get; set; } = 18f; + + public bool Enabled { get; set; } = true; + + public Color Color { get; set; } + + private TimeSince TimeSinceCreated = 0; + + [GameEvent.Tick.Client] + public void OnTick() + { + if ( !(TimeSinceCreated > Math.Clamp(MurderGame.MaxFootprintTime, 0, 30)) ) + { + return; + } + + Enabled = false; + Delete(); + } + + public override void DoRender(SceneObject obj) + { + if (!Enabled) return; + + // Allow lights to affect the sprite + Graphics.SetupLighting(obj); + // Create the vertex buffer for the sprite + var vb = new VertexBuffer(); + vb.Init(true); + + // Vertex buffers are in local space, so we need the camera position in local space too + var normal = new Vector3( 0, 0.01f, 100 ); + var w = normal.Cross(Vector3.Down).Normal; + var h = normal.Cross(w).Normal; + float halfSpriteSize = SpriteScale / 2; + + // Add a single quad to our vertex buffer + vb.AddQuad(new Ray(default, normal), halfSpriteSize*w, h*halfSpriteSize); + + Graphics.Attributes.Set( "color", Color); + + // Draw the sprite + vb.Draw( SpriteMaterial ); + } +} diff --git a/code/pawn/Player.Character.cs b/code/pawn/Player.Character.cs index a8fc19c..579107a 100644 --- a/code/pawn/Player.Character.cs +++ b/code/pawn/Player.Character.cs @@ -5,10 +5,17 @@ namespace MurderGame; public partial class Player { [Net] public Team Team { get; set; } - + [Net] public string CharacterName { get; set; } - [Net] public string HexColor { get; set; } + [Net] public Color Color { get; set; } = Color.White; + + public string HexColor { + get + { + return Color.Hex; + } + } public string GetTeamName() { diff --git a/code/pawn/Player.cs b/code/pawn/Player.cs index 7073bb1..7254023 100644 --- a/code/pawn/Player.cs +++ b/code/pawn/Player.cs @@ -47,6 +47,7 @@ public partial class Player : AnimatedEntity [BindComponent] public AnimatorComponent Animator { get; } [BindComponent] public InventoryComponent Inventory { get; } [BindComponent] public FallDamageComponent FallDamage { get; } + [BindComponent] public FootprintTrackerComponent FootprintTracker { get; } [Net] public Ragdoll PlayerRagdoll { get; set; } @@ -179,6 +180,7 @@ public partial class Player : AnimatedEntity Animator?.Simulate(); Inventory?.Simulate( cl ); FallDamage?.Simulate( cl ); + FootprintTracker?.Simulate( cl ); if (Game.IsServer && Camera is not SpectatorCameraComponent && LifeState == LifeState.Dead && TimeSinceDeath > 3.5) { diff --git a/code/pawn/component/FootprintTrackerComponent.cs b/code/pawn/component/FootprintTrackerComponent.cs new file mode 100644 index 0000000..7a396d1 --- /dev/null +++ b/code/pawn/component/FootprintTrackerComponent.cs @@ -0,0 +1,51 @@ +using System.Linq; +using Sandbox; + +namespace MurderGame; + +public class FootprintTrackerComponent : EntityComponent, ISingletonComponent +{ + private TimeSince TimeSinceFootstep = 0; + private bool FootstepLeft = true; + + public void Simulate( IClient cl ) + { + if (!Game.IsClient || TimeSinceFootstep < 0.25) return; + TimeSinceFootstep = 0; + FootstepLeft = !FootstepLeft; + + var bystanders = Game.Clients.Where(c => (c.Pawn as Player)?.Team is Team.Bystander or Team.Detective); + + foreach (var bystander in bystanders) + { + if (bystander.Pawn is not Player player) continue; + if (player.Velocity.Length < 1) continue; + var start = player.Position + Vector3.Up; + var end = start + Vector3.Down * 20; + + var tr = Trace.Ray( start, end ) + .Size( 2) + .WithAnyTags( "solid" ) + .Ignore( Entity ) + .Run(); + + if ( !tr.Hit ) + { + continue; + } + + var material = FootstepLeft + ? "materials/left_shoe_footprint.vmat" + : "materials/right_shoe_footprint.vmat"; + var _ = new Footprint + { + SpriteMaterial = Material.Load(material), + SpriteScale = 24f, + Position = player.Position + (Vector3.Up * 1f), + Rotation = Rotation.LookAt(player.Velocity, tr.Normal).RotateAroundAxis( tr.Normal, 270 ), + Color = player.Color + }; + } + } + +} diff --git a/code/phase/AssignPhase.cs b/code/phase/AssignPhase.cs index f29aa62..f69ca7b 100644 --- a/code/phase/AssignPhase.cs +++ b/code/phase/AssignPhase.cs @@ -3,11 +3,10 @@ using Sandbox.UI; using System; using System.Collections.Generic; using System.Linq; -using System.Net.Http.Headers; namespace MurderGame; -public class AssignPhase : BasePhase +public partial class AssignPhase : BasePhase { public override string Title => "Assigning teams"; public int TicksElapsed; @@ -42,18 +41,18 @@ public class AssignPhase : BasePhase "Zulu" }; - private List HexColours = new() + private List Colors = new() { - "#0074D9", // blue - "#7FDBFF", // aqua - "#39CCCC", // teal - "#F012BE", // fuchsia - "#FF4136", // red - "#FF851B", // orange - "#FFDC00", // yellow - "#3D9970", // olive - "#2ECC40", // lime - "#01FF70" // green + 0x0074D9, // blue + 0x7FDBFF, // aqua + 0x39CCCC, // teal + 0xF012BE, // fuchsia + 0xFF4136, // red + 0xFF851B, // orange + 0xFFDC00, // yellow + 0x3D9970, // olive + 0x2ECC40, // lime + 0x01FF70 // green }; public override void Activate() @@ -63,17 +62,18 @@ public class AssignPhase : BasePhase { entity.Delete(); } + DeleteFootprints(); // cleanup -- end var detectivesNeeded = 1; var murderersNeeded = 1; - Random random = new(); + Random random = new(Guid.NewGuid().GetHashCode()); var spawnPoints = Entity.All.OfType().OrderBy( _ => random.Next() ).ToList(); var clients = Game.Clients.ToList().OrderBy( _ => random.Next() ); var natoNamesRemaining = new List(NatoNames.OrderBy( _ => random.Next() )); - var coloursRemaining = new List(HexColours.OrderBy( _ => random.Next() )); + var colorsRemaining = new List(Colors.OrderBy( _ => random.Next() )); foreach ( var client in clients ) { @@ -99,9 +99,9 @@ public class AssignPhase : BasePhase { natoNamesRemaining = new List(NatoNames); } - if (coloursRemaining.Count == 0) + if (colorsRemaining.Count == 0) { - coloursRemaining = new List(HexColours); + colorsRemaining = new List(Colors); } // assign team @@ -134,15 +134,24 @@ public class AssignPhase : BasePhase pawn.CharacterName = natoName; // assign nato name - var hexColour = coloursRemaining[0]; - coloursRemaining.RemoveAt( 0 ); - pawn.HexColor = hexColour; + var hexColor = colorsRemaining[0]; + colorsRemaining.RemoveAt( 0 ); + pawn.Color = Color.FromRgb(hexColor); RoleOverlay.Show( To.Single( client ) ); } base.TimeLeft = 5; } + [ClientRpc] + public static void DeleteFootprints() + { + foreach (var entity in Entity.All.OfType()) + { + entity.Delete(); + } + } + public override void Deactivate() { foreach (var client in Game.Clients) diff --git a/code/team/Team.cs b/code/team/Team.cs index 189840b..ef065a4 100644 --- a/code/team/Team.cs +++ b/code/team/Team.cs @@ -54,6 +54,7 @@ public static class TeamCapabilities private static void GiveMurdererWeapon(Player pawn) { pawn.Inventory.SetPrimaryWeapon( new Knife() ); + pawn.Components.Create(); } } public static class TeamOperations diff --git a/materials/left_shoe_footprint.png b/materials/left_shoe_footprint.png new file mode 100644 index 0000000..ef4e0e0 Binary files /dev/null and b/materials/left_shoe_footprint.png differ diff --git a/materials/left_shoe_footprint.vmat b/materials/left_shoe_footprint.vmat new file mode 100644 index 0000000..5c5a56e --- /dev/null +++ b/materials/left_shoe_footprint.vmat @@ -0,0 +1,49 @@ +// THIS FILE IS AUTO-GENERATED + +Layer0 +{ + shader "shaders/static_overlay.shader" + + //---- Blend Mode ---- + F_BLEND_MODE 1 // Translucent + + //---- Ambient Occlusion ---- + TextureAmbientOcclusion "materials/default/default_ao.tga" + + //---- Color ---- + g_flModelTintAmount "1.000" + g_vColorTint "[1.000000 1.000000 1.000000 0.000000]" + TextureColor "materials/left_shoe_footprint.png" + + //---- Fade ---- + g_flFadeExponent "1.000" + + //---- Fog ---- + g_bFogEnabled "1" + + //---- Metalness ---- + g_flMetalness "0.000" + + //---- Normal ---- + TextureNormal "materials/default/default_normal.tga" + + //---- Roughness ---- + g_flRoughnessScaleFactor "1.000" + TextureRoughness "materials/default/default_rough.tga" + + //---- Texture Coordinates ---- + g_nScaleTexCoordUByModelScaleAxis "0" + g_nScaleTexCoordVByModelScaleAxis "0" + g_vTexCoordOffset "[0.000 0.000]" + g_vTexCoordScale "[1.000 1.000]" + g_vTexCoordScrollSpeed "[0.000 0.000]" + + //---- Translucent ---- + g_flOpacityScale "1.000" + TextureTranslucency "materials/left_shoe_footprint.png" + + DynamicParams + { + g_vColorTint "color" + } +} \ No newline at end of file diff --git a/materials/right_shoe_footprint.png b/materials/right_shoe_footprint.png new file mode 100644 index 0000000..9bb5137 Binary files /dev/null and b/materials/right_shoe_footprint.png differ diff --git a/materials/right_shoe_footprint.vmat b/materials/right_shoe_footprint.vmat new file mode 100644 index 0000000..b58586f --- /dev/null +++ b/materials/right_shoe_footprint.vmat @@ -0,0 +1,49 @@ +// THIS FILE IS AUTO-GENERATED + +Layer0 +{ + shader "shaders/static_overlay.shader" + + //---- Blend Mode ---- + F_BLEND_MODE 1 // Translucent + + //---- Ambient Occlusion ---- + TextureAmbientOcclusion "materials/default/default_ao.tga" + + //---- Color ---- + g_flModelTintAmount "1.000" + g_vColorTint "[0.925490 0.925490 0.925490 1.000000]" + TextureColor "materials/right_shoe_footprint.png" + + //---- Fade ---- + g_flFadeExponent "1.000" + + //---- Fog ---- + g_bFogEnabled "1" + + //---- Metalness ---- + g_flMetalness "0.000" + + //---- Normal ---- + TextureNormal "materials/default/default_normal.tga" + + //---- Roughness ---- + g_flRoughnessScaleFactor "1.000" + TextureRoughness "materials/default/default_rough.tga" + + //---- Texture Coordinates ---- + g_nScaleTexCoordUByModelScaleAxis "0" + g_nScaleTexCoordVByModelScaleAxis "0" + g_vTexCoordOffset "[0.000 0.000]" + g_vTexCoordScale "[1.000 1.000]" + g_vTexCoordScrollSpeed "[0.000 0.000]" + + //---- Translucent ---- + g_flOpacityScale "1.000" + TextureTranslucency "materials/right_shoe_footprint.png" + + DynamicParams + { + g_vColorTint "color" + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2