/// <summary> /// Cause recoil in the specified direction, no effect if shaking /// </summary> /// <param name="dir">direction to recoil</param> /// <param name="cameraRecoilConfig">configuration for the recoil</param> public void Recoil(Vector2 dir, CameraRecoilConfig cameraRecoilConfig) { if (isShaking) { return; } this.activeRecoilConfig = cameraRecoilConfig; if (recoilOffsetDestination != Vector2.zero) { //recoil from current position Vector2 newRecoilOffsetDestination = recoilOffset + dir.normalized * activeRecoilConfig.Distance; //cap it so we don't recoil further than the maximum from our origin if (newRecoilOffsetDestination.magnitude > activeRecoilConfig.Distance) { newRecoilOffsetDestination = dir.normalized * activeRecoilConfig.Distance; } recoilOffsetDestination = newRecoilOffsetDestination; //ensure we will reach our max recoil sooner based on how close we already our to our recoil destination float distanceFromDestination = (recoilOffset - recoilOffsetDestination).magnitude; float distanceFromOrigin = recoilOffsetDestination.magnitude; recoilTime = activeRecoilConfig.RecoilDuration * (distanceFromDestination / distanceFromOrigin); } else { //begin recoiling recoilOffsetDestination = dir.normalized * activeRecoilConfig.Distance; recoilTime = activeRecoilConfig.RecoilDuration; } }
/// <summary> /// Perform and display the shot locally (i.e. only on this instance of the game). Does not /// communicate anything to other players (unless this is the server, in which case the server /// will determine the effects of the bullet). Does not do any validation. This should only be invoked /// when displaying the results of a shot (i.e. after receiving a ShootMessage or after this client performs a shot) /// or when server is determining the outcome of the shot. /// </summary> /// <param name="shooter">gameobject of the shooter</param> /// <param name="finalDirection">direction the shot should travel (accuracy deviation should already be factored into this)</param> /// <param name="damageZone">targeted damage zone</param> /// <param name="isSuicideShot">if this is a suicide shot (aimed at shooter)</param> public void DisplayShot(GameObject shooter, Vector2 finalDirection, BodyPartType damageZone, bool isSuicideShot) { //if this is our gun (or server), last check to ensure we really can shoot if ((isServer || PlayerManager.LocalPlayer == shooter) && CurrentMagazine.ClientAmmoRemains <= 0) { if (isServer) { Logger.LogTrace("Server rejected shot - out of ammo", Category.Firearms); } return; } //Add too the cooldown timer to being allowed to shoot again FireCountDown += 1.0 / FireRate; CurrentMagazine.ExpendAmmo(); //get the bullet prefab being shot GameObject bullet = PoolManager.PoolClientInstantiate(Resources.Load(Projectile.name) as GameObject, shooter.transform.position); BulletBehaviour b = bullet.GetComponent <BulletBehaviour>(); if (isSuicideShot) { b.Suicide(shooter, this, damageZone); } else { b.Shoot(finalDirection, shooter, this, damageZone); } //add additional recoil after shooting for the next round AppendRecoil(); SoundManager.PlayAtPosition(FiringSound, shooter.transform.position); //jerk screen back based on recoil angle and power if (shooter == PlayerManager.LocalPlayer) { //Default recoil params until each gun is configured separately if (CameraRecoilConfig == null || CameraRecoilConfig.Distance == 0f) { CameraRecoilConfig = new CameraRecoilConfig { Distance = 0.2f, RecoilDuration = 0.05f, RecoveryDuration = 0.6f }; } Camera2DFollow.followControl.Recoil(-finalDirection, CameraRecoilConfig); } shooter.GetComponent <PlayerSprites>().ShowMuzzleFlash(); }
/// <summary> /// Perform and display the shot locally (i.e. only on this instance of the game). Does not /// communicate anything to other players (unless this is the server, in which case the server /// will determine the effects of the bullet). Does not do any validation. This should only be invoked /// when displaying the results of a shot (i.e. after receiving a ShootMessage or after this client performs a shot) /// or when server is determining the outcome of the shot. /// </summary> /// <param name="shooter">gameobject of the shooter</param> /// <param name="finalDirection">direction the shot should travel (accuracy deviation should already be factored into this)</param> /// <param name="damageZone">targeted damage zone</param> /// <param name="isSuicideShot">if this is a suicide shot (aimed at shooter)</param> public void DisplayShot(GameObject shooter, Vector2 finalDirection, BodyPartType damageZone, bool isSuicideShot) { //if this is our gun (or server), last check to ensure we really can shoot if ((isServer || PlayerManager.LocalPlayer == shooter) && CurrentMagazine.ClientAmmoRemains <= 0) { if (isServer) { Logger.LogTrace("Server rejected shot - out of ammo", Category.Firearms); } return; } //TODO: If this is not our gun, simply display the shot, don't run any other logic if (shooter == PlayerManager.LocalPlayer) { //this is our gun so we need to update our predictions FireCountDown += 1.0 / FireRate; //add additional recoil after shooting for the next round AppendRecoil(); //Default camera recoil params until each gun is configured separately if (CameraRecoilConfig == null || CameraRecoilConfig.Distance == 0f) { CameraRecoilConfig = new CameraRecoilConfig { Distance = 0.2f, RecoilDuration = 0.05f, RecoveryDuration = 0.6f }; } Camera2DFollow.followControl.Recoil(-finalDirection, CameraRecoilConfig); } //call ExpendAmmo outside of previous check, or it won't run serverside and state will desync. CurrentMagazine.ExpendAmmo(); //display the effects of the shot //get the bullet prefab being shot GameObject bullet = Spawn.ClientPrefab(Resources.Load(Projectile.name) as GameObject, shooter.transform.position).GameObject; BulletBehaviour b = bullet.GetComponent <BulletBehaviour>(); if (isSuicideShot) { b.Suicide(shooter, this, damageZone); } else { b.Shoot(finalDirection, shooter, this, damageZone); } SoundManager.PlayAtPosition(FiringSound, shooter.transform.position); shooter.GetComponent <PlayerSprites>().ShowMuzzleFlash(); }
public virtual void OnSpawnServer(SpawnInfo info) { if (MagInternal) { //automatic ejection always disabled SmartGun = false; //ejecting an internal mag should never be allowed allowMagazineRemoval = false; } //Default recoil if one has not been set already if (CameraRecoilConfig == null || CameraRecoilConfig.Distance == 0f) { var Recoil = new CameraRecoilConfig { Distance = 0.2f, RecoilDuration = 0.05f, RecoveryDuration = 0.6f }; SyncCameraRecoilConfig(CameraRecoilConfig, Recoil); } if (ammoPrefab == null) { Logger.LogError($"{gameObject.name} magazine prefab was null, cannot auto-populate.", Category.Firearms); return; } //populate with a full external mag on spawn Logger.LogTraceFormat("Auto-populate external magazine for {0}", Category.Firearms, name); Inventory.ServerAdd(Spawn.ServerPrefab(ammoPrefab).GameObject, magSlot); if (pinPrefab == null) { Logger.LogError($"{gameObject.name} firing pin prefab was null, cannot auto-populate.", Category.Firearms); return; } Inventory.ServerAdd(Spawn.ServerPrefab(pinPrefab).GameObject, pinSlot); FiringPin.gunComp = this; if (suppressorPrefab != null && isSuppressed && isSuppressible) { Inventory.ServerAdd(Spawn.ServerPrefab(suppressorPrefab).GameObject, suppressorSlot); } }
/// <summary> /// Perform and display the shot locally (i.e. only on this instance of the game). Does not /// communicate anything to other players (unless this is the server, in which case the server /// will determine the effects of the bullet). Does not do any validation. This should only be invoked /// when displaying the results of a shot (i.e. after receiving a ShootMessage or after this client performs a shot) /// or when server is determining the outcome of the shot. /// </summary> /// <param name="shooter">gameobject of the shooter</param> /// <param name="finalDirection">direction the shot should travel (accuracy deviation should already be factored into this)</param> /// <param name="damageZone">targeted damage zone</param> /// <param name="isSuicideShot">if this is a suicide shot (aimed at shooter)</param> public void DisplayShot(GameObject shooter, Vector2 finalDirection, BodyPartType damageZone, bool isSuicideShot) { //Add too the cooldown timer to being allowed to shoot again FireCountDown += 1.0 / FireRate; CurrentMagazine.ammoRemains--; //get the bullet prefab being shot GameObject bullet = PoolManager.PoolClientInstantiate(Resources.Load(Projectile.name) as GameObject, shooter.transform.position); float angle = Mathf.Atan2(finalDirection.y, finalDirection.x) * Mathf.Rad2Deg; BulletBehaviour b = bullet.GetComponent <BulletBehaviour>(); if (isSuicideShot) { b.Suicide(shooter, this, damageZone); } else { b.Shoot(finalDirection, shooter, this, damageZone); } //add additional recoil after shooting for the next round AppendRecoil(angle); SoundManager.PlayAtPosition(FiringSound, shooter.transform.position); //jerk screen back based on recoil angle and power if (shooter == PlayerManager.LocalPlayer) { //Default recoil params until each gun is configured separately if (CameraRecoilConfig == null || CameraRecoilConfig.Distance == 0f) { CameraRecoilConfig = new CameraRecoilConfig { Distance = 0.2f, RecoilDuration = 0.05f, RecoveryDuration = 0.6f }; } Camera2DFollow.followControl.Recoil(-finalDirection, CameraRecoilConfig); } shooter.GetComponent <PlayerSprites>().ShowMuzzleFlash(); }
/// <summary> /// Perform and display the shot locally (i.e. only on this instance of the game). Does not /// communicate anything to other players (unless this is the server, in which case the server /// will determine the effects of the bullet). Does not do any validation. This should only be invoked /// when displaying the results of a shot (i.e. after receiving a ShootMessage or after this client performs a shot) /// or when server is determining the outcome of the shot. /// </summary> /// <param name="shooter">gameobject of the shooter</param> /// <param name="finalDirection">direction the shot should travel (accuracy deviation should already be factored into this)</param> /// <param name="damageZone">targeted damage zone</param> /// <param name="isSuicideShot">if this is a suicide shot (aimed at shooter)</param> public void DisplayShot(GameObject shooter, Vector2 finalDirection, BodyPartType damageZone, bool isSuicideShot, string projectileName, int quantity) { if (!MatrixManager.IsInitialized) { return; } //if this is our gun (or server), last check to ensure we really can shoot if (isServer || PlayerManager.LocalPlayer == shooter) { if (CurrentMagazine.ClientAmmoRemains <= 0) { if (isServer) { Logger.LogTrace("Server rejected shot - out of ammo", Category.Firearms); } return; } CurrentMagazine.ExpendAmmo(); } //TODO: If this is not our gun, simply display the shot, don't run any other logic if (shooter == PlayerManager.LocalPlayer) { //this is our gun so we need to update our predictions FireCountDown += 1.0 / FireRate; //add additional recoil after shooting for the next round AppendRecoil(); //Default camera recoil params until each gun is configured separately if (CameraRecoilConfig == null || CameraRecoilConfig.Distance == 0f) { CameraRecoilConfig = new CameraRecoilConfig { Distance = 0.2f, RecoilDuration = 0.05f, RecoveryDuration = 0.6f }; } Camera2DFollow.followControl.Recoil(-finalDirection, CameraRecoilConfig); } if (isSuicideShot) { GameObject bullet = Spawn.ClientPrefab(projectileName, shooter.transform.position, parent: shooter.transform.parent).GameObject; var b = bullet.GetComponent <Projectile>(); b.Suicide(shooter, this, damageZone); } else { for (int n = 0; n < quantity; n++) { GameObject Abullet = Spawn.ClientPrefab(projectileName, shooter.transform.position, parent: shooter.transform.parent).GameObject; var A = Abullet.GetComponent <Projectile>(); var finalDirectionOverride = CalcDirection(finalDirection, n); A.Shoot(finalDirectionOverride, shooter, this, damageZone); } } SoundManager.PlayAtPosition(FiringSound, shooter.transform.position, shooter); shooter.GetComponent <PlayerSprites>().ShowMuzzleFlash(); }
/// <summary> /// Syncs the recoil config. /// </summary> public void SyncCameraRecoilConfig(CameraRecoilConfig oldValue, CameraRecoilConfig newValue) { CameraRecoilConfig = newValue; }
/// <summary> /// Perform and display the shot locally (i.e. only on this instance of the game). Does not /// communicate anything to other players (unless this is the server, in which case the server /// will determine the effects of the bullet). Does not do any validation. This should only be invoked /// when displaying the results of a shot (i.e. after receiving a ShootMessage or after this client performs a shot) /// or when server is determining the outcome of the shot. /// </summary> /// <param name="shooter">gameobject of the shooter</param> /// <param name="finalDirection">direction the shot should travel (accuracy deviation should already be factored into this)</param> /// <param name="damageZone">targeted damage zone</param> /// <param name="isSuicideShot">if this is a suicide shot (aimed at shooter)</param> public void DisplayShot(GameObject shooter, Vector2 finalDirection, BodyPartType damageZone, bool isSuicideShot) { if (!MatrixManager.IsInitialized) { return; } //if this is our gun (or server), last check to ensure we really can shoot if ((isServer || PlayerManager.LocalPlayer == shooter) && CurrentMagazine.ClientAmmoRemains <= 0) { if (isServer) { Logger.LogTrace("Server rejected shot - out of ammo", Category.Firearms); } return; } if (shooter == PlayerManager.LocalPlayer) { //this is our gun so we need to update our predictions FireCountDown += 1.0 / FireRate; //add additional recoil after shooting for the next round AppendRecoil(); //Default camera recoil params until each gun is configured separately if (CameraRecoilConfig == null || CameraRecoilConfig.Distance == 0f) { CameraRecoilConfig = new CameraRecoilConfig { Distance = 0.2f, RecoilDuration = 0.05f, RecoveryDuration = 0.6f }; } Camera2DFollow.followControl.Recoil(-finalDirection, CameraRecoilConfig); if (CurrentMagazine == null) { Logger.LogWarning($"Why is {nameof(CurrentMagazine)} null for {this} on this client?"); } else { //call ExpendAmmo outside of previous check, or it won't run serverside and state will desync. CurrentMagazine.ExpendAmmo(); } } MagazineBehaviour magazine = ammoPrefab.GetComponent <MagazineBehaviour>(); if (isSuicideShot) { GameObject bullet = Spawn.ClientPrefab(magazine.Projectile.name, shooter.transform.position, parent: shooter.transform.parent).GameObject; var b = bullet.GetComponent <Projectile>(); b.Suicide(shooter, this, damageZone); } else { for (int n = 0; n < magazine.ProjectilesFired; n++) { GameObject Abullet = Spawn.ClientPrefab(magazine.Projectile.name, shooter.transform.position, parent: shooter.transform.parent).GameObject; var A = Abullet.GetComponent <Projectile>(); var finalDirectionOverride = CalcDirection(finalDirection, n); A.Shoot(finalDirectionOverride, shooter, this, damageZone); } } SoundManager.PlayAtPosition(FiringSound, shooter.transform.position, shooter); shooter.GetComponent <PlayerSprites>().ShowMuzzleFlash(); }