using AlienAttack.MonoGame.Things.Bullets; using AlienAttack.MonoGame.Things.Muzzles; using Microsoft.Xna.Framework; using System.Linq; namespace AlienAttack.MonoGame.Things.Weapons; public abstract class Weapon : IWeapon { public abstract int FireThreshold { get; } public int CurrentFireThreshold { get; private set; } public void UpdateFireThreshold() { if (CurrentFireThreshold > 0) CurrentFireThreshold--; } public bool TryFire(Sprite owner, SpriteUpdateContext context) { if (CurrentFireThreshold > 0) return false; Fire(owner, context); CurrentFireThreshold = FireThreshold; return true; } public abstract void Fire(Sprite owner, SpriteUpdateContext context); protected static void FireBullet(FireBulletContext context) { var (x, y) = ComputeAnchorPosition(context); foreach (Shot shot in context.Shots) { Bullet bullet = context.Factory(x + shot.OffsetX, y + shot.OffsetY, shot.XVelocity, shot.YVelocity, context.Owner); context.SpriteUpdateContext.SpawnSprite(bullet); } } private static (float x, float y) ComputeAnchorPosition(FireBulletContext context) { Sprite owner = context.Owner; int bw = context.BulletWidth; int bh = context.BulletHeight; Anchor anchor = context.Anchor; float left = owner.XPosition; float top = owner.YPosition; float right = owner.XPosition + owner.BoundBox.Width; float bottom = owner.YPosition + owner.BoundBox.Height; return anchor switch { Anchor.TopLeft => (left, top - bh), Anchor.TopCenter => (left + (owner.BoundBox.Width - bw) / 2f, top - bh), Anchor.TopRight => (right - bw, top - bh), Anchor.Center => (left + (owner.BoundBox.Width - bw) / 2f, top + (owner.BoundBox.Height - bh) / 2f), Anchor.BottomLeft => (left, bottom), Anchor.BottomCenter => (left + (owner.BoundBox.Width - bw) / 2f, bottom), Anchor.BottomRight => (right - bw, bottom), _ => (left, top) }; } protected static void FireFromMuzzle(FireBulletFromMuzzleContext context) { if (context.Owner is not Player player) return; foreach (MuzzleShot shot in context.Shots) { var m = player.Muzzles.First(x => x.Id == shot.Muzzle).LocalPx; Vector2 worldMuzzle = MuzzleMath.GetMuzzleWorld(player, m); Vector2 bulletPos = MuzzleMath.CenterBulletOn(worldMuzzle, context.BulletWidth, context.BulletHeight) + context.ExtraOffset; Bullet bullet = context.Factory(bulletPos.X, bulletPos.Y, shot.XVelocity, shot.YVelocity, context.Owner); context.SpriteUpdateContext.SpawnSprite(bullet); } } }