public async void ResolveTriggerPull() { try { // Both debouncing and conceptually letting the gun's mechanism cycle - two birds, one rock! if (DateTime.Now < nextReadyTime) { return; } lastTriggerPull = DateTime.Now; nextReadyTime = DateTime.Now + Weapon.CooldownPeriod; // Is the weapon being pointed up? var AngleToGravity = Gravity.Vector.AngleTo(Weapon.vectorPointedForward); if (AngleToGravity < 30) { Weapon.ReloadSFX?.Play(useSpeakers: true); nextReadyTime += Weapon.ReloadTime; while (Weapon.CurrentAmmoCount < Weapon.MaxAmmoCapacity) { await Task.Delay((int)(Weapon.ReloadTime.TotalMilliseconds / (Weapon.MaxAmmoCapacity + 1))); //await Task.Delay((int)(Weapon.ReloadTime.TotalMilliseconds / Weapon.MaxAmmoCapacity)); Current.SetBulletDisplay(++Weapon.CurrentAmmoCount); //Weapon.ClickEmptySFX.Play(0.5); // Stand-in for the currently null ReloadSFX. } return; } // Or... is it being pointed down? We've coded that to be "change fire mode." if (AngleToGravity > 150) { if (!Weapon.SupportsBurstFire && !Weapon.SupportsFullAutomatic) { Speech.Say("This weapon supports single shot mode only.", SoundOptions.OnHeadphones); return; } if (Weapon.CurrentFireMode == Gun.FireMode.SingleShot) { if (Weapon.SupportsBurstFire) { Weapon.CurrentFireMode = Gun.FireMode.BurstFire; } else if (Weapon.SupportsFullAutomatic) { Weapon.CurrentFireMode = Gun.FireMode.FullAuto; } } else if (Weapon.CurrentFireMode == Gun.FireMode.BurstFire) { if (Weapon.SupportsFullAutomatic) { Weapon.CurrentFireMode = Gun.FireMode.FullAuto; } else { Weapon.CurrentFireMode = Gun.FireMode.SingleShot; } } else { Weapon.CurrentFireMode = Gun.FireMode.SingleShot; } Speech.Say(Weapon.CurrentFireMode.ToString(), SoundOptions.OnHeadphones); return; } // Okay. Are they out of ammo? if (Weapon.CurrentAmmoCount == 0) { await(Weapon.ClickEmptySFX?.PlayToCompletion(null, true) ?? Task.CompletedTask); return; } Weapon.CurrentAmmoCount--; Current.SetBulletDisplay(Weapon.CurrentAmmoCount); exhaleCueHasBeenProvided = false; await Task.WhenAll(Task.Delay(150).ContinueWith(_ => CrossVibrate.Current.Vibration(50)), Weapon.ShotSFX.PlayToCompletion(1.0, true)); await Task.Delay(random.Next(100, 400)); // Do the dice rolls now var DidHit = DidItHit(); // And assess the results one way or the other bool DoResultSFX; double ResultSFXVolume; if (DidHit) { DoResultSFX = random.Next(1, 20) < 17; ResultSFXVolume = 0.25 * (3.0 + Math.Max(random.NextDouble(), random.NextDouble())); Current.AddKillTallymark(); } else { DoResultSFX = random.Next(1, 20) < 11; ResultSFXVolume = random.NextDouble(); } // Play the SFX depending on hit/miss status and the odds (within each) of an audible response. Not every wound/ricochet is audible! if (DoResultSFX) { if (DidHit) { ShotHitSFX.Play(ResultSFXVolume, useSpeakers: true); // Experimental!! Atropos.Communications.HeyYou.MyTeammates.PlaySFX(ShotHitSFX); } else { ShotMissSFX.Play(ResultSFXVolume, useSpeakers: true); // Experimental!! Atropos.Communications.HeyYou.MyTeammates.PlaySFX(ShotMissSFX); } } // Testing the new Evasion code here... for now after every third shot. if (Weapon.CurrentAmmoCount % 3 == 0) { var Incoming = new IncomingRangedAttack(); EvasionMode <Vector3> Evasion = (Res.CoinFlip) ? new EvasionMode.Dodge() : new EvasionMode.Duck(); var EvasionStage = new IncomingAttackPrepStage <Vector3>(Current, Incoming, Evasion); EvasionStage.Activate(); } } catch (Exception) { throw; } }