Russian roulette now ends after a player dies. Still need to let the minigame manager know and add logic for moving to the next game, cleanup, ending a round, etc
This commit is contained in:
@@ -58,6 +58,7 @@ public partial class Pawn : AnimatedEntity
|
||||
|
||||
[BindComponent] public UserPawnController Controller { get; }
|
||||
[BindComponent] public PawnAnimator Animator { get; }
|
||||
[BindComponent] public PawnInventory Inventory { get; }
|
||||
|
||||
public override Ray AimRay => new Ray( EyePosition, EyeRotation.Forward );
|
||||
|
||||
@@ -71,12 +72,7 @@ public partial class Pawn : AnimatedEntity
|
||||
EnableDrawing = true;
|
||||
EnableHideInFirstPerson = true;
|
||||
EnableShadowInFirstPerson = true;
|
||||
}
|
||||
|
||||
public void Respawn()
|
||||
{
|
||||
Components.Create<UserPawnController>();
|
||||
Components.Create<PawnAnimator>();
|
||||
SetupPhysicsFromModel( PhysicsMotionType.Keyframed );
|
||||
}
|
||||
|
||||
public void DressFromClient( IClient cl )
|
||||
@@ -91,6 +87,7 @@ public partial class Pawn : AnimatedEntity
|
||||
SimulateRotation();
|
||||
Controller?.Simulate( cl );
|
||||
Animator?.Simulate();
|
||||
Inventory?.ActiveWeapon?.Simulate( cl );
|
||||
}
|
||||
|
||||
public override void BuildInput()
|
||||
@@ -130,4 +127,15 @@ public partial class Pawn : AnimatedEntity
|
||||
EyeRotation = Rotation.Slerp( Rotation, idealRotation, Time.Delta * 10f );
|
||||
Rotation = EyeRotation;
|
||||
}
|
||||
|
||||
public void LookAt( Vector3 position )
|
||||
{
|
||||
Rotation = Rotation.LookAt( (position - this.Position).Normal, Vector3.Up );
|
||||
EyePosition = position;
|
||||
}
|
||||
|
||||
public override void TakeDamage( DamageInfo info )
|
||||
{
|
||||
base.TakeDamage( info );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public partial class RoundManager : Entity
|
||||
/// <summary>
|
||||
/// The number of seconds from the timer starting before the round starts
|
||||
/// </summary>
|
||||
private const float RoundStartCountdownSeconds = 10f;
|
||||
private const float RoundStartCountdownSeconds = 5f;
|
||||
|
||||
/// <summary>
|
||||
/// The state of the current round
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Sandbox;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -26,6 +27,9 @@ public partial class Weapon : AnimatedEntity
|
||||
public virtual string ReloadAnimPath => "reload";
|
||||
public virtual string WeaponName => "weapon";
|
||||
public virtual float ReloadDuration => 4f;
|
||||
public virtual CitizenAnimationHelper.HoldTypes HoldType { get; }
|
||||
protected virtual List<string> HitTags => new List<string> { "solid", "player", "npc" };
|
||||
protected virtual float Damage => 20f;
|
||||
private bool Reloading => TimeSinceReloadStarted < ReloadDuration;
|
||||
|
||||
/// <summary>
|
||||
@@ -68,6 +72,7 @@ public partial class Weapon : AnimatedEntity
|
||||
SetParent( pawn, true );
|
||||
EnableDrawing = true;
|
||||
CreateViewModel( To.Single( pawn ) );
|
||||
pawn.SetAnimParameter( "holdtype", (int)HoldType );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,6 +82,7 @@ public partial class Weapon : AnimatedEntity
|
||||
{
|
||||
EnableDrawing = false;
|
||||
DestroyViewModel( To.Single( Owner ) );
|
||||
Pawn.SetAnimParameter( "holdtype", (int)CitizenAnimationHelper.HoldTypes.None );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -128,7 +134,7 @@ public partial class Weapon : AnimatedEntity
|
||||
/// <returns></returns>
|
||||
public virtual bool CanPrimaryAttack()
|
||||
{
|
||||
if ( !Owner.IsValid() || !Input.Down( "attack1" ) || Ammo == 0 || Reloading ) return false;
|
||||
if ( !Owner.IsValid() || !Input.Down( "attack1" ) || (Ammo == 0 && MaxAmmo != 0) || Reloading ) return false;
|
||||
|
||||
var rate = PrimaryRate;
|
||||
if ( rate <= 0 ) return true;
|
||||
@@ -138,7 +144,7 @@ public partial class Weapon : AnimatedEntity
|
||||
|
||||
private void ReduceAmmoAndPrimaryAttack()
|
||||
{
|
||||
Ammo--;
|
||||
Ammo = Math.Max(0, Ammo -1);
|
||||
PrimaryAttack();
|
||||
}
|
||||
|
||||
@@ -166,7 +172,7 @@ public partial class Weapon : AnimatedEntity
|
||||
|
||||
var trace = Trace.Ray( start, end )
|
||||
.UseHitboxes()
|
||||
.WithAnyTags( "solid", "player", "npc" )
|
||||
.WithAnyTags( HitTags.ToArray() )
|
||||
.Ignore( this )
|
||||
.Size( radius );
|
||||
|
||||
|
||||
54
code/EntityComponents/Pawn/PawnInventory.cs
Normal file
54
code/EntityComponents/Pawn/PawnInventory.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LuckerGame.Entities.Weapons;
|
||||
using Sandbox;
|
||||
|
||||
namespace LuckerGame.Components.Pawn;
|
||||
|
||||
public partial class PawnInventory : EntityComponent<Entities.Pawn>
|
||||
{
|
||||
[Net] private List<Weapon> Weapons { get; set; } = new List<Weapon>();
|
||||
[Net, Predicted] public Weapon ActiveWeapon { get; private set; }
|
||||
|
||||
public List<Weapon> GetWeapons()
|
||||
{
|
||||
return Weapons.ToList();
|
||||
}
|
||||
|
||||
public bool AddWeapon( Weapon weapon )
|
||||
{
|
||||
if ( Weapons.Any( w => w.GetType() == weapon.GetType() ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Weapons.Add( weapon );
|
||||
if ( Weapons.Count == 1 )
|
||||
{
|
||||
SetActiveWeapon( weapon );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void NextWeapon()
|
||||
{
|
||||
if ( ActiveWeapon == null )
|
||||
{
|
||||
ActiveWeapon = Weapons.FirstOrDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
var weaponIndex = Weapons.IndexOf( ActiveWeapon );
|
||||
var nextIndex = (weaponIndex + 1) % Weapons.Count;
|
||||
var weapon = Weapons[nextIndex];
|
||||
SetActiveWeapon( weapon );
|
||||
}
|
||||
|
||||
public void SetActiveWeapon( Weapon weapon )
|
||||
{
|
||||
ActiveWeapon?.OnHolster();
|
||||
ActiveWeapon = weapon;
|
||||
ActiveWeapon.OnEquip( Entity );
|
||||
}
|
||||
}
|
||||
53
code/Minigames/RussianRoulette/RussianPistol.cs
Normal file
53
code/Minigames/RussianRoulette/RussianPistol.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LuckerGame.Entities.Weapons;
|
||||
using Sandbox;
|
||||
|
||||
namespace LuckerGame.Minigames.RussianRoulette;
|
||||
|
||||
public partial class RussianPistol : Weapon
|
||||
{
|
||||
public override string ModelPath => "weapons/rust_pistol/rust_pistol.vmdl";
|
||||
public override string ViewModelPath => "weapons/rust_pistol/v_rust_pistol.vmdl";
|
||||
|
||||
public override string WeaponName => "Russian Pistol";
|
||||
|
||||
protected override List<string> HitTags => new List<string> { "victim" };
|
||||
|
||||
public override CitizenAnimationHelper.HoldTypes HoldType => CitizenAnimationHelper.HoldTypes.Pistol;
|
||||
|
||||
public override int MaxAmmo => 6;
|
||||
|
||||
protected override float Damage => 1000f;
|
||||
|
||||
[ClientRpc]
|
||||
protected virtual void ShootEffects()
|
||||
{
|
||||
Game.AssertClient();
|
||||
|
||||
Particles.Create( "particles/pistol_muzzleflash.vpcf", EffectEntity, "muzzle" );
|
||||
|
||||
Pawn.SetAnimParameter( "b_attack", true );
|
||||
ViewModelEntity?.SetAnimParameter( "fire", true );
|
||||
}
|
||||
|
||||
public override void PrimaryAttack()
|
||||
{
|
||||
if ( Random.Shared.Next( 1, Ammo + 1 ) == 1)
|
||||
{
|
||||
ShootEffects();
|
||||
Pawn.PlaySound( "rust_pistol.shoot" );
|
||||
ShootBullet( 0.01f, 100, Damage, 10 );
|
||||
}
|
||||
else
|
||||
{
|
||||
Pawn.PlaySound( "denyundo" );
|
||||
}
|
||||
Ammo--;
|
||||
}
|
||||
|
||||
protected override void Animate()
|
||||
{
|
||||
Pawn.SetAnimParameter( "holdtype", (int)CitizenAnimationHelper.HoldTypes.Pistol );
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using LuckerGame.Components.Lucker.Cameras;
|
||||
using LuckerGame.Components.Pawn;
|
||||
using LuckerGame.Entities;
|
||||
using Sandbox;
|
||||
using Sandbox.UI;
|
||||
|
||||
namespace LuckerGame.Minigames.RussianRoulette;
|
||||
|
||||
[Library("mg_russian_roulette")]
|
||||
public class RussianRouletteMinigame : Minigame
|
||||
{
|
||||
public override string Name => "Russian Roulette";
|
||||
private List<Lucker> Players { get; set; }
|
||||
private Pawn Shooter { get; set; }
|
||||
private const float ShooterDistance = 50f;
|
||||
private const int CardinalDirections = 4;
|
||||
private const float ShooterDistance = 80f;
|
||||
private const float TimeBetweenShots = 7f;
|
||||
private int Taunted = 0;
|
||||
|
||||
private List<Pawn> DeadVictims => Players
|
||||
.Select( player => player.Pawn as Pawn )
|
||||
.Where( pawn => !pawn.IsValid || pawn.LifeState != LifeState.Alive )
|
||||
.ToList();
|
||||
|
||||
private TimeSince TimeSinceShot { get; set; }
|
||||
|
||||
public override void Initialize( List<Lucker> players )
|
||||
{
|
||||
Players = players;
|
||||
Shooter = new Pawn();
|
||||
|
||||
/*// Spawn shooter at a random spawnpoint
|
||||
var spawnpoints = Entity.All.OfType<SpawnPoint>();
|
||||
var randomSpawnPoint = spawnpoints.OrderBy( x => Guid.NewGuid() ).FirstOrDefault();
|
||||
var tx = randomSpawnPoint.Transform;
|
||||
tx.Position = tx.Position + Vector3.Up * 50.0f; // raise it up
|
||||
Shooter.Position = tx.Position;*/
|
||||
var shooterInventory = Shooter.Components.Create<PawnInventory>();
|
||||
shooterInventory.AddWeapon( new RussianPistol() );
|
||||
|
||||
// Setup cameras for players
|
||||
Players.ForEach( player =>
|
||||
@@ -39,18 +46,55 @@ public class RussianRouletteMinigame : Minigame
|
||||
var player = pair.Player;
|
||||
var index = pair.Index;
|
||||
var pawn = new Pawn();
|
||||
pawn.Name = player.Name;
|
||||
pawn.Tags.Add( "victim" );
|
||||
pawn.Health = 1;
|
||||
player.Pawn = pawn;
|
||||
pawn.DressFromClient( player.Client );
|
||||
|
||||
var pawnOffset = ShooterDistance * (index % 2 == 0 ? Vector3.Forward : Vector3.Right) * (index % 4 >= 2 ? -1 : 1);
|
||||
|
||||
player.Pawn.Position = Shooter.Position + pawnOffset;
|
||||
pawn.LookAt(Shooter.Position);
|
||||
} );
|
||||
TimeSinceShot = 0;
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
{
|
||||
return;
|
||||
if ( DeadVictims.Any() )
|
||||
{
|
||||
if ( Taunted != int.MaxValue )
|
||||
{
|
||||
ChatBox.AddChatEntry( To.Everyone, "Shooter", "Heh, nothing personnel, kid." );
|
||||
Taunted = int.MaxValue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( TimeSinceShot > TimeBetweenShots )
|
||||
{
|
||||
TimeSinceShot = 0;
|
||||
Taunted = 0;
|
||||
Shooter.Inventory.ActiveWeapon.PrimaryAttack();
|
||||
if ( !DeadVictims.Any() )
|
||||
{
|
||||
ChatBox.AddChatEntry( To.Everyone, "Shooter", "Fucking lag..." );
|
||||
}
|
||||
}
|
||||
else if ( TimeSinceShot > TimeBetweenShots * .8f && Taunted == 1)
|
||||
{
|
||||
var victim = Players.Select( player => player.Pawn as Pawn )
|
||||
.OrderBy( _ => Guid.NewGuid() )
|
||||
.FirstOrDefault();
|
||||
Shooter.LookAt( victim.Position );
|
||||
ChatBox.AddChatEntry( To.Everyone, "Shooter", $"I'm gonna eat you up, {victim.Name}" );
|
||||
Taunted++;
|
||||
}
|
||||
else if ( TimeSinceShot > TimeBetweenShots / 2 && Taunted == 0)
|
||||
{
|
||||
ChatBox.AddChatEntry( To.Everyone, "Shooter", "Im gettin' ready!" );
|
||||
Taunted++;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Cleanup()
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<VotingLobby/>
|
||||
<Scoreboard/>
|
||||
<CameraCursor/>
|
||||
|
||||
</root>
|
||||
|
||||
@code
|
||||
|
||||
Reference in New Issue
Block a user