private void InitSystems(RenderTarget target) { DisplaySystem displaySystem = new DisplaySystem(target); systems.Add(displaySystem); MoveSystem moveSystem = new MoveSystem(); systems.Add(moveSystem); CollisionSystem collisionSystem = new CollisionSystem(target); systems.Add(collisionSystem); ThrowingSystem throwingSystem = new ThrowingSystem(); systems.Add(throwingSystem); DilayedStartSystem dilayedStartSystem = new DilayedStartSystem(); systems.Add(dilayedStartSystem); }
public override void Shoot(GunComponent gun, List <IShootable> ammo, EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid?user = null) { var fromMap = fromCoordinates.ToMap(EntityManager); var toMap = toCoordinates.ToMapPos(EntityManager); var mapDirection = toMap - fromMap.Position; var mapAngle = mapDirection.ToAngle(); var angle = GetRecoilAngle(Timing.CurTime, gun, mapDirection.ToAngle()); // Update shot based on the recoil toMap = fromMap.Position + angle.ToVec() * mapDirection.Length; mapDirection = toMap - fromMap.Position; var entityDirection = Transform(fromCoordinates.EntityId).InvWorldMatrix.Transform(toMap) - fromCoordinates.Position; // I must be high because this was getting tripped even when true. // DebugTools.Assert(direction != Vector2.Zero); var shotProjectiles = new List <EntityUid>(ammo.Count); foreach (var shootable in ammo) { switch (shootable) { // Cartridge shoots something else case CartridgeAmmoComponent cartridge: if (!cartridge.Spent) { if (cartridge.Count > 1) { var angles = LinearSpread(mapAngle - cartridge.Spread / 2, mapAngle + cartridge.Spread / 2, cartridge.Count); for (var i = 0; i < cartridge.Count; i++) { var uid = Spawn(cartridge.Prototype, fromCoordinates); ShootProjectile(uid, angles[i].ToVec(), user); shotProjectiles.Add(uid); } } else { var uid = Spawn(cartridge.Prototype, fromCoordinates); ShootProjectile(uid, mapDirection, user); shotProjectiles.Add(uid); } SetCartridgeSpent(cartridge, true); MuzzleFlash(gun.Owner, cartridge, user); PlaySound(gun.Owner, gun.SoundGunshot?.GetSound(Random, ProtoManager), user); if (cartridge.DeleteOnSpawn) { Del(cartridge.Owner); } } else { PlaySound(gun.Owner, gun.SoundEmpty?.GetSound(Random, ProtoManager), user); } // Something like ballistic might want to leave it in the container still if (!cartridge.DeleteOnSpawn && !Containers.IsEntityInContainer(cartridge.Owner)) { EjectCartridge(cartridge.Owner); } Dirty(cartridge); break; // Ammo shoots itself case AmmoComponent newAmmo: shotProjectiles.Add(newAmmo.Owner); MuzzleFlash(gun.Owner, newAmmo, user); PlaySound(gun.Owner, gun.SoundGunshot?.GetSound(Random, ProtoManager), user); // Do a throw if (!HasComp <ProjectileComponent>(newAmmo.Owner)) { RemComp <AmmoComponent>(newAmmo.Owner); // TODO: Someone can probably yeet this a billion miles so need to pre-validate input somewhere up the call stack. ThrowingSystem.TryThrow(newAmmo.Owner, mapDirection, 20f, user); break; } ShootProjectile(newAmmo.Owner, mapDirection, user); break; case HitscanPrototype hitscan: var ray = new CollisionRay(fromMap.Position, mapDirection.Normalized, hitscan.CollisionMask); var rayCastResults = Physics.IntersectRay(fromMap.MapId, ray, hitscan.MaxLength, user, false).ToList(); if (rayCastResults.Count >= 1) { var result = rayCastResults[0]; var distance = result.Distance; FireEffects(fromCoordinates, distance, entityDirection.ToAngle(), hitscan, result.HitEntity); var dmg = hitscan.Damage; if (dmg != null) { dmg = Damageable.TryChangeDamage(result.HitEntity, dmg); } if (dmg != null) { PlayImpactSound(result.HitEntity, dmg, hitscan.Sound, hitscan.ForceSound); if (user != null) { Logs.Add(LogType.HitScanHit, $"{ToPrettyString(user.Value):user} hit {ToPrettyString(result.HitEntity):target} using hitscan and dealt {dmg.Total:damage} damage"); } else { Logs.Add(LogType.HitScanHit, $"Hit {ToPrettyString(result.HitEntity):target} using hitscan and dealt {dmg.Total:damage} damage"); } } } else { FireEffects(fromCoordinates, hitscan.MaxLength, entityDirection.ToAngle(), hitscan); } PlaySound(gun.Owner, gun.SoundGunshot?.GetSound(Random, ProtoManager), user); break; default: throw new ArgumentOutOfRangeException(); } } RaiseLocalEvent(gun.Owner, new AmmoShotEvent() { FiredProjectiles = shotProjectiles, }, false); }