From 2660c14d22d274b181bdc541b717d027e60e3c93 Mon Sep 17 00:00:00 2001 From: theg33ka Date: Tue, 30 Jun 2026 21:12:29 +0700 Subject: [PATCH 1/6] added fox3torpedo --- .../ForgeTorpedoLauncherComponent.cs | 50 ++++ .../ShipWeapons/ForgeTorpedoLauncherSystem.cs | 275 ++++++++++++++++++ .../_Mono/FireControl/FireControlSystem.cs | 44 ++- .../TargetSeeking/TargetSeekingSystem.cs | 23 +- .../en-US/_Forge/research/ship_weapons.ftl | 1 + .../Locale/en-US/_Forge/ship_weapons.ftl | 1 + .../ru-RU/_Forge/research/ship_weapons.ftl | 1 + .../Locale/ru-RU/_Forge/ship_weapons.ftl | 1 + .../Circuitboards/Machine/ship_weapons.yml | 12 + .../Entities/SpaceArtillery/heavy_torpedo.yml | 191 ++++++++++++ .../Recipes/Lathes/Packs/ship_weapons.yml | 1 + .../_Forge/Recipes/Lathes/ship_weapons.yml | 5 + .../_Forge/Research/ship_weapons.yml | 13 + 13 files changed, 606 insertions(+), 12 deletions(-) create mode 100644 Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs create mode 100644 Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs create mode 100644 Resources/Locale/en-US/_Forge/ship_weapons.ftl create mode 100644 Resources/Locale/ru-RU/_Forge/ship_weapons.ftl create mode 100644 Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml diff --git a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs new file mode 100644 index 00000000000..710425a45f0 --- /dev/null +++ b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs @@ -0,0 +1,50 @@ +using Content.Shared.Physics; + +namespace Content.Server._Forge.ShipWeapons; + +/// +/// Marks a ship weapon as a torpedo launcher that only needs a clear muzzle lane +/// instead of full line of sight to the gunnery cursor. +/// +[RegisterComponent] +public sealed partial class ForgeTorpedoLauncherComponent : Component +{ + /// + /// Distance from the launcher center used to sample the tile in front of the muzzle. + /// That tile must be empty/space, because torpedoes prefer vacuum over chewing the hull. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float TileProbeDistance = 1f; + + /// + /// Short physics ray distance used to catch hard blockers immediately in front of the muzzle. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float ClearanceRayDistance = 1.25f; + + /// + /// Collision mask for the short muzzle clearance ray. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int ClearanceCollisionMask = (int) (CollisionGroup.Opaque | CollisionGroup.Impassable); + + /// + /// Distance used to build a gun shoot coordinate straight out of the launcher. + /// The actual locked target is stored separately, because the cursor is not the muzzle direction. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float LaunchAimDistance = 32f; + + /// + /// How far from the gunnery cursor the launcher may look for a grid to lock. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float TargetSearchRadius = 48f; + + /// + /// Minimum amount of tiles a grid needs to be considered a torpedo target. + /// This keeps expensive fireworks from chasing loose scrap, because why would it. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int MinTargetTiles = 25; +} diff --git a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs new file mode 100644 index 00000000000..8614c8e8ec9 --- /dev/null +++ b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs @@ -0,0 +1,275 @@ +using System.Numerics; +using Content.Server._Mono.Projectiles.TargetSeeking; +using Content.Shared.Examine; +using Content.Shared.Maps; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Systems; + +namespace Content.Server._Forge.ShipWeapons; + +public sealed class ForgeTorpedoLauncherSystem : EntitySystem +{ + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly TargetSeekingSystem _targetSeeking = default!; + [Dependency] private readonly TurfSystem _turf = default!; + + private List> _targetGridScratch = new(); + private readonly Dictionary _pendingTargets = new(); + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnAmmoShot); + SubscribeLocalEvent(OnShutdown); + } + + private void OnExamined(EntityUid uid, ForgeTorpedoLauncherComponent component, ExaminedEvent args) + { + if (!args.IsInDetailsRange) + return; + + args.PushMarkup(Loc.GetString("forge-torpedo-launcher-examine")); + } + + private void OnShutdown(EntityUid uid, ForgeTorpedoLauncherComponent component, ComponentShutdown args) + { + _pendingTargets.Remove(uid); + } + + private void OnAmmoShot(EntityUid uid, ForgeTorpedoLauncherComponent component, AmmoShotEvent args) + { + if (args.FiredProjectiles.Count == 0) + { + return; + } + + if (!_pendingTargets.Remove(uid, out var targetGrid)) + { + if (!TryComp(uid, out var gun) || + gun.ShootCoordinates is not { } aimCoordinates || + !TryFindTargetGrid(uid, aimCoordinates, component, Transform(uid), out targetGrid)) + { + return; + } + } + + if (!Exists(targetGrid)) + return; + + foreach (var projectile in args.FiredProjectiles) + { + if (!TryComp(projectile, out var seeking)) + continue; + + _targetSeeking.SetSeekerTarget((projectile, seeking), targetGrid, Transform(projectile)); + } + } + + public Vector2 GetLaunchDirection(TransformComponent xform) + { + return _transform.GetWorldRotation(xform).ToWorldVec(); + } + + public bool TryPrepareLaunch( + EntityUid uid, + EntityCoordinates aimCoordinates, + Vector2 launchDirection, + ForgeTorpedoLauncherComponent? component, + TransformComponent? xform, + out EntityCoordinates launchCoordinates) + { + launchCoordinates = default; + _pendingTargets.Remove(uid); + + if (!Resolve(uid, ref component, ref xform)) + return false; + + if (launchDirection.LengthSquared() <= 0.0001f) + return false; + + launchDirection = Vector2.Normalize(launchDirection); + + if (!CanLaunch(uid, launchDirection, component, xform) || + !TryFindTargetGrid(uid, aimCoordinates, component, xform, out var targetGrid)) + { + return false; + } + + var launcherCoords = _transform.GetMapCoordinates(xform); + var launchMapCoordinates = new MapCoordinates( + launcherCoords.Position + launchDirection * component.LaunchAimDistance, + launcherCoords.MapId); + + launchCoordinates = _transform.ToCoordinates((uid, xform), launchMapCoordinates); + _pendingTargets[uid] = targetGrid; + return true; + } + + public bool CanLaunch( + EntityUid uid, + Vector2 worldDirection, + ForgeTorpedoLauncherComponent? component = null, + TransformComponent? xform = null) + { + if (!Resolve(uid, ref component, ref xform)) + return false; + + if (worldDirection.LengthSquared() <= 0.0001f) + return false; + + if (xform.GridUid is not { } gridUid || !TryComp(gridUid, out var grid)) + return false; + + worldDirection = Vector2.Normalize(worldDirection); + + return HasSpaceAhead(gridUid, grid, xform, worldDirection, component) && + HasClearMuzzleRay(uid, gridUid, xform, worldDirection, component); + } + + public bool TryFindTargetGrid( + EntityUid uid, + EntityCoordinates aimCoordinates, + ForgeTorpedoLauncherComponent? component, + TransformComponent? xform, + out EntityUid targetGrid) + { + targetGrid = default; + + if (!Resolve(uid, ref component, ref xform)) + return false; + + var aimMapCoordinates = _transform.ToMapCoordinates(aimCoordinates); + if (aimMapCoordinates.MapId != xform.MapID) + return false; + + var searchRadius = MathF.Max(0f, component.TargetSearchRadius); + var searchExtents = new Vector2(searchRadius, searchRadius); + var searchBox = new Box2( + aimMapCoordinates.Position - searchExtents, + aimMapCoordinates.Position + searchExtents); + + _targetGridScratch.Clear(); + _mapManager.FindGridsIntersecting(aimMapCoordinates.MapId, searchBox, ref _targetGridScratch, approx: true, includeMap: false); + + var sourceGrid = xform.GridUid; + var bestDistance = float.MaxValue; + + for (var i = 0; i < _targetGridScratch.Count; i++) + { + var candidate = _targetGridScratch[i]; + var candidateUid = candidate.Owner; + + if (candidateUid == sourceGrid || + TerminatingOrDeleted(candidateUid) || + !HasEnoughTiles(candidateUid, candidate.Comp, component.MinTargetTiles)) + { + continue; + } + + var candidateXform = Transform(candidateUid); + if (candidateXform.MapID != aimMapCoordinates.MapId) + continue; + + var bounds = _transform.GetWorldMatrix(candidateXform).TransformBox(candidate.Comp.LocalAABB); + var distance = DistanceSquaredToBox(aimMapCoordinates.Position, bounds); + if (distance >= bestDistance) + continue; + + bestDistance = distance; + targetGrid = candidateUid; + } + + _targetGridScratch.Clear(); + return targetGrid != default; + } + + private bool HasSpaceAhead( + EntityUid gridUid, + MapGridComponent grid, + TransformComponent launcherXform, + Vector2 worldDirection, + ForgeTorpedoLauncherComponent component) + { + var launcherCoords = _transform.GetMapCoordinates(launcherXform); + var probeCoords = launcherCoords.Offset(worldDirection * component.TileProbeDistance); + var probeTile = _map.TileIndicesFor(gridUid, grid, probeCoords); + + if (!_map.TryGetTileRef(gridUid, grid, probeTile, out var tileRef)) + return true; + + return tileRef.Tile.IsEmpty || + _turf.GetContentTileDefinition(tileRef).ID == ContentTileDefinition.SpaceID; + } + + private bool HasClearMuzzleRay( + EntityUid uid, + EntityUid gridUid, + TransformComponent launcherXform, + Vector2 worldDirection, + ForgeTorpedoLauncherComponent component) + { + var launcherCoords = _transform.GetMapCoordinates(launcherXform); + var ray = new CollisionRay( + launcherCoords.Position, + worldDirection, + collisionMask: component.ClearanceCollisionMask); + + foreach (var _ in _physics.IntersectRayWithPredicate( + launcherXform.MapID, + ray, + uid, + IgnoreNonMuzzleBlockers, + component.ClearanceRayDistance, + returnOnFirstHit: true)) + { + return false; + } + + return true; + + bool IgnoreNonMuzzleBlockers(EntityUid entity, EntityUid source) + { + if (entity == source) + return true; + + if (!TryComp(entity, out var otherXform)) + return false; + + return otherXform.GridUid != gridUid; + } + } + + private bool HasEnoughTiles(EntityUid gridUid, MapGridComponent grid, int minimumTiles) + { + if (minimumTiles <= 0) + return true; + + var count = 0; + var enumerator = _map.GetAllTilesEnumerator(gridUid, grid); + while (enumerator.MoveNext(out _)) + { + count++; + if (count >= minimumTiles) + return true; + } + + return false; + } + + private static float DistanceSquaredToBox(Vector2 point, Box2 box) + { + var dx = MathF.Max(MathF.Max(box.Left - point.X, 0f), point.X - box.Right); + var dy = MathF.Max(MathF.Max(box.Bottom - point.Y, 0f), point.Y - box.Top); + + return dx * dx + dy * dy; + } +} diff --git a/Content.Server/_Mono/FireControl/FireControlSystem.cs b/Content.Server/_Mono/FireControl/FireControlSystem.cs index 631cfeaf26e..d857a842f3b 100644 --- a/Content.Server/_Mono/FireControl/FireControlSystem.cs +++ b/Content.Server/_Mono/FireControl/FireControlSystem.cs @@ -35,6 +35,7 @@ public sealed partial class FireControlSystem : EntitySystem [Dependency] private PowerReceiverSystem _power = default!; [Dependency] private RotateToFaceSystem _rotateToFace = default!; [Dependency] private ShipWeaponHomeGridSystem _shipWeaponHomeGrid = default!; // Forge-Change + [Dependency] private ForgeTorpedoLauncherSystem _forgeTorpedoLauncher = default!; // Forge-Change /// /// Dictionary of entities that have visualization enabled /// @@ -43,6 +44,7 @@ public sealed partial class FireControlSystem : EntitySystem private EntityQuery _artilleryQuery; private EntityQuery _fireRotateQuery; private EntityQuery _gunQuery; + private EntityQuery _forgeTorpedoLauncherQuery; // Forge-Change public override void Initialize() { @@ -66,6 +68,7 @@ public override void Initialize() _artilleryQuery = GetEntityQuery(); _fireRotateQuery = GetEntityQuery(); _gunQuery = GetEntityQuery(); + _forgeTorpedoLauncherQuery = GetEntityQuery(); // Forge-Change } private void OnPowerChanged(EntityUid uid, FireControlServerComponent component, PowerChangedEvent args) @@ -528,23 +531,46 @@ public bool AttemptFire(EntityUid weapon, EntityUid user, EntityCoordinates coor var weaponPos = weaponCoords.Position; var targetCoords = coords.ToMap(EntityManager, _xform); var targetPos = targetCoords.Position; + var fireCoords = coords; // Calculate direction var direction = targetPos - weaponPos; - var distance = direction.Length(); - if (distance <= float.Epsilon) - return false; // Can't fire at the same position - direction = Vector2.Normalize(direction); + // Forge-Change-Start: torpedo launchers are static tubes. The cursor picks a + // target grid, but the launch vector comes from the tube's own orientation. + if (_forgeTorpedoLauncherQuery.TryComp(weapon, out var torpedoLauncher)) + { + direction = _forgeTorpedoLauncher.GetLaunchDirection(weaponXform); + + if (!_forgeTorpedoLauncher.TryPrepareLaunch( + weapon, + coords, + direction, + torpedoLauncher, + weaponXform, + out fireCoords)) + { + return false; + } + } + // Forge-Change-End + else + { + var distance = direction.Length(); + if (distance <= float.Epsilon) + return false; // Can't fire at the same position - // Check for obstacles in the firing direction - if (!CanFireInDirection(weapon, weaponPos, direction, targetPos, weaponXform.MapID)) - return false; + direction = Vector2.Normalize(direction); + + // Check for obstacles in the firing direction + if (!CanFireInDirection(weapon, weaponPos, direction, targetPos, weaponXform.MapID)) + return false; + } // Set the cooldown for next firing comp.NextFire = _timing.CurTime + TimeSpan.FromSeconds(comp.FireCooldown); - if (_fireRotateQuery.HasComp(weapon)) + if (!_forgeTorpedoLauncherQuery.HasComp(weapon) && _fireRotateQuery.HasComp(weapon)) // Forge-Change: torpedo shafts stay static. { var goalAngle = Angle.FromWorldVec(direction); _rotateToFace.TryRotateTo(weapon, goalAngle, 0f, Angle.FromDegrees(1), float.MaxValue, weaponXform); @@ -553,7 +579,7 @@ public bool AttemptFire(EntityUid weapon, EntityUid user, EntityCoordinates coor // Try to get a gun component and fire the weapon if (_gunQuery.TryComp(weapon, out var gun)) { - _gun.AttemptShots(user, weapon, gun, coords, TimeSpan.FromSeconds(0.2)); + _gun.AttemptShots(user, weapon, gun, fireCoords, TimeSpan.FromSeconds(0.2)); return true; } diff --git a/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs b/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs index dcc2030476f..d6c77a75524 100644 --- a/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs +++ b/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs @@ -3,6 +3,7 @@ using Content.Server.Shuttles.Components; using Content.Shared.Projectiles; using Robust.Server.GameObjects; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -297,7 +298,7 @@ public void AcquireTarget(EntityUid uid, TargetSeekingComponent component, Trans public Angle ApplyPredictiveTracking(Entity ent, Entity target, float frameTime) { // Get current positions - var currentTargetPosition = _transform.GetWorldPosition(target.Comp2); + var currentTargetPosition = GetTargetWorldPosition(target); var sourcePosition = _transform.GetWorldPosition(ent.Comp3); // Calculate current distance @@ -336,7 +337,7 @@ public Angle ApplyAdvancedTracking(Entity ent, Entity target, float frameTime) { // Get the angle directly toward the target - var angleToTarget = (_transform.GetWorldPosition(target.Comp) - _transform.GetWorldPosition(ent.Comp)).ToWorldAngle(); + var angleToTarget = (GetTargetWorldPosition(target) - _transform.GetWorldPosition(ent.Comp)).ToWorldAngle(); return angleToTarget; } + + private Vector2 GetTargetWorldPosition(Entity target) + { + if (TryComp(target.Owner, out var grid)) + return Vector2.Transform(grid.LocalAABB.Center, _transform.GetWorldMatrix(target.Comp)); + + return _transform.GetWorldPosition(target.Comp); + } + + private Vector2 GetTargetWorldPosition(Entity target) + { + if (TryComp(target.Owner, out var grid)) + return Vector2.Transform(grid.LocalAABB.Center, _transform.GetWorldMatrix(target.Comp2)); + + return _transform.GetWorldPosition(target.Comp2); + } } diff --git a/Resources/Locale/en-US/_Forge/research/ship_weapons.ftl b/Resources/Locale/en-US/_Forge/research/ship_weapons.ftl index 9a2b31e7a6b..7d88f8a1faf 100644 --- a/Resources/Locale/en-US/_Forge/research/ship_weapons.ftl +++ b/Resources/Locale/en-US/_Forge/research/ship_weapons.ftl @@ -14,6 +14,7 @@ forge-research-technology-shipweapon-prometheus = Prometheus Laser Cannon forge-research-technology-shipweapon-serpent = Serpent Torpedo Launcher forge-research-technology-shipweapon-tovek = TOVEK Missile Pod forge-research-technology-shipweapon-trident = Trident Torpedo Rack +forge-research-technology-shipweapon-heavy-torpedo = Gungnir Heavy Torpedo Launcher forge-research-technology-shipweapon-light-munitions-bay = Light Munitions Bay forge-research-technology-shipweapon-longbow = Longbow Autocannon forge-research-technology-shipweapon-cyrexa = CYREXA Cannon diff --git a/Resources/Locale/en-US/_Forge/ship_weapons.ftl b/Resources/Locale/en-US/_Forge/ship_weapons.ftl new file mode 100644 index 00000000000..3e153ec9d33 --- /dev/null +++ b/Resources/Locale/en-US/_Forge/ship_weapons.ftl @@ -0,0 +1 @@ +forge-torpedo-launcher-examine = It can launch torpedoes without direct line of sight, but the muzzle must point into empty space. diff --git a/Resources/Locale/ru-RU/_Forge/research/ship_weapons.ftl b/Resources/Locale/ru-RU/_Forge/research/ship_weapons.ftl index 608fcb171de..54b46c0f6c2 100644 --- a/Resources/Locale/ru-RU/_Forge/research/ship_weapons.ftl +++ b/Resources/Locale/ru-RU/_Forge/research/ship_weapons.ftl @@ -14,6 +14,7 @@ forge-research-technology-shipweapon-prometheus = Лазер «Прометей forge-research-technology-shipweapon-serpent = Торпедный аппарат «Змея» forge-research-technology-shipweapon-tovek = Ракетная установка TOVEK forge-research-technology-shipweapon-trident = Торпедная установка «Трезубец» +forge-research-technology-shipweapon-heavy-torpedo = Тяжёлая торпедная установка «Гунгнир» forge-research-technology-shipweapon-light-munitions-bay = Лёгкий бомболюк forge-research-technology-shipweapon-longbow = Автопушка Longbow forge-research-technology-shipweapon-cyrexa = Пушка CYREXA diff --git a/Resources/Locale/ru-RU/_Forge/ship_weapons.ftl b/Resources/Locale/ru-RU/_Forge/ship_weapons.ftl new file mode 100644 index 00000000000..11c1ba35ebc --- /dev/null +++ b/Resources/Locale/ru-RU/_Forge/ship_weapons.ftl @@ -0,0 +1 @@ +forge-torpedo-launcher-examine = Может запускать торпеды без прямой видимости цели, но дуло должно смотреть в пустой космос. diff --git a/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml b/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml index 52538c19cf8..03a880fd8f6 100644 --- a/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml +++ b/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml @@ -396,6 +396,18 @@ tags: - MachineBoard2x2 +- type: entity + id: WeaponTurretForgeHeavyTorpedoCircuitboard + parent: ForgeShipWeaponCircuitboardT4 + name: FHT-300 Gungnir heavy torpedo launcher machine board + description: A machine printed circuit board for an FHT-300 Gungnir heavy torpedo launcher. Ships love not needing line of sight, captains love not asking why. + components: + - type: MachineBoard + prototype: WeaponTurretForgeHeavyTorpedoPortable + - type: Tag + tags: + - MachineBoard2x2 + - type: entity id: WeaponTurretDrakeApolloMk2Circuitboard parent: ForgeShipWeaponCircuitboardT4 diff --git a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml new file mode 100644 index 00000000000..b09ca032efe --- /dev/null +++ b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml @@ -0,0 +1,191 @@ +- type: entity + id: WeaponTurretForgeHeavyTorpedo + name: FHT-300 "Gungnir" heavy torpedo launcher + suffix: For mapping + parent: + - BallisticArtilleryMapped + - BallisticArtilleryTier4HP + description: A heavy Forge torpedo launcher that can fire from the hull without direct target line of sight. The muzzle still needs open vacuum; firing into your own plating is a bold plan, but why? + components: + - type: StaticPrice + price: 18000 + - type: Sprite + sprite: _Mono/Objects/ShuttleWeapons/asm220.rsi + layers: + - state: space_artillery + - type: Appearance + - type: ForgeTorpedoLauncher + - type: AmmoCounter + - type: Battery + maxCharge: 90000 + startingCharge: 90000 + - type: ExaminableBattery + - type: WirelessNetworkConnection + range: 500 + - type: Gun + fireRate: 0.08 + recoil: 20 + minAngle: 0 + maxAngle: 0 + shootThermalSignature: 48000000 + soundGunshot: + path: /Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg + soundEmpty: + path: /Audio/Weapons/Guns/EmptyAlarm/smg_empty_alarm.ogg + - type: SpaceArtillery + powerChargeRate: 600 + powerUsePassive: 1800 + powerUseActive: 0 + - type: BatterySelfRecharger + autoRecharge: true + autoRechargeRate: 250 + - type: Actions + - type: ProjectileBatteryAmmoProvider + proto: ShipTorpedoForgeHeavy + fireCost: 30000 + - type: RadarBlip + radarColor: "#ff9d00" + scale: 2.5 + visibleFromOtherGrids: true + gridConfig: + color: "#ff9d00" + shape: Square + respectZoom: true + rotate: true + bounds: "-1.5,-1.5,1.5,1.5" + - type: ShipGunType + shipType: Missile + - type: ShipGunClass + shipClass: Superheavy + - type: ShipRepairable + repairTime: 45 + repairCost: 160 + +- type: entity + id: WeaponTurretForgeHeavyTorpedoPortable + name: FHT-300 "Gungnir" heavy torpedo launcher + suffix: DO NOT MAP + parent: + - BallisticArtillery + - BallisticArtilleryTier4HP + description: A heavy Forge torpedo launcher that can fire from the hull without direct target line of sight. The muzzle still needs open vacuum; firing into your own plating is a bold plan, but why? + components: + - type: StaticPrice + price: 18000 + - type: Sprite + sprite: _Mono/Objects/ShuttleWeapons/asm220.rsi + layers: + - state: space_artillery + - type: Appearance + - type: ForgeTorpedoLauncher + - type: AmmoCounter + - type: Battery + maxCharge: 90000 + startingCharge: 90000 + - type: ExaminableBattery + - type: WirelessNetworkConnection + range: 500 + - type: Gun + fireRate: 0.08 + recoil: 20 + minAngle: 0 + maxAngle: 0 + shootThermalSignature: 48000000 + soundGunshot: + path: /Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg + soundEmpty: + path: /Audio/Weapons/Guns/EmptyAlarm/smg_empty_alarm.ogg + - type: SpaceArtillery + powerChargeRate: 600 + powerUsePassive: 1800 + powerUseActive: 0 + - type: BatterySelfRecharger + autoRecharge: true + autoRechargeRate: 250 + - type: Actions + - type: ProjectileBatteryAmmoProvider + proto: ShipTorpedoForgeHeavy + fireCost: 30000 + - type: RadarBlip + radarColor: "#ff9d00" + scale: 2.5 + visibleFromOtherGrids: true + gridConfig: + color: "#ff9d00" + shape: Square + respectZoom: true + rotate: true + bounds: "-1.5,-1.5,1.5,1.5" + - type: ShipGunType + shipType: Missile + - type: ShipGunClass + shipClass: Superheavy + - type: ShipRepairable + repairTime: 45 + repairCost: 160 + +- type: entity + id: ShipTorpedoForgeHeavy + name: FHT-300 heavy torpedo + parent: BaseTorpedo + categories: [ HideSpawnMenu ] + components: + - type: Projectile + damage: + types: + Structural: 4500 + Blunt: 900 + Heat: 450 + - type: Sprite + sprite: _Mono/Objects/SpaceArtillery/mini_rocket.rsi + layers: + - state: mini-rocket + scale: 1, 2 + - type: Ammo + muzzleFlash: null + - type: ShipWeaponProjectile + - type: RadarBlip + radarColor: "#ff9d00" + scale: 4 + shape: triangle + - type: TimedDespawn + lifetime: 22 + - type: PointLight + radius: 5 + color: orange + energy: 2 + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Default + totalIntensity: 2500 + intensitySlope: 35 + maxIntensity: 220 + - type: GatheringProjectile + - type: MiningGatheringSoft + - type: MiningGatheringHard + - type: TargetSeeking + acceleration: 45 + detectionRange: 850 + scanArc: 55 + launchSpeed: 35 + maxSpeed: 90 + trackDelay: 2 + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic + - type: Meteor + damageTypes: + types: + Blunt: 1 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 1200 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:ExplodeBehavior + - !type:PlaySoundBehavior + sound: + collection: MetalBreak diff --git a/Resources/Prototypes/_Forge/Recipes/Lathes/Packs/ship_weapons.yml b/Resources/Prototypes/_Forge/Recipes/Lathes/Packs/ship_weapons.yml index 72de0e30f98..704579f7d0b 100644 --- a/Resources/Prototypes/_Forge/Recipes/Lathes/Packs/ship_weapons.yml +++ b/Resources/Prototypes/_Forge/Recipes/Lathes/Packs/ship_weapons.yml @@ -24,3 +24,4 @@ - WeaponTurretCyrexaCircuitboard - WeaponTurretCharonReloadCircuitboard - WeaponLaserTurretApolloCircuitboard + - WeaponTurretForgeHeavyTorpedoCircuitboard diff --git a/Resources/Prototypes/_Forge/Recipes/Lathes/ship_weapons.yml b/Resources/Prototypes/_Forge/Recipes/Lathes/ship_weapons.yml index 8003c62a486..9e30a3477f6 100644 --- a/Resources/Prototypes/_Forge/Recipes/Lathes/ship_weapons.yml +++ b/Resources/Prototypes/_Forge/Recipes/Lathes/ship_weapons.yml @@ -182,3 +182,8 @@ parent: ForgeShipWeaponBoardRecipeT4 id: WeaponLaserTurretApolloCircuitboard result: WeaponLaserTurretApolloCircuitboard + +- type: latheRecipe + parent: ForgeShipWeaponBoardRecipeT4 + id: WeaponTurretForgeHeavyTorpedoCircuitboard + result: WeaponTurretForgeHeavyTorpedoCircuitboard diff --git a/Resources/Prototypes/_Forge/Research/ship_weapons.yml b/Resources/Prototypes/_Forge/Research/ship_weapons.yml index db45848f8dd..374871b4b5d 100644 --- a/Resources/Prototypes/_Forge/Research/ship_weapons.yml +++ b/Resources/Prototypes/_Forge/Research/ship_weapons.yml @@ -252,6 +252,19 @@ - ForgeShipWeaponResearchSerpent position: -11, 8 +- type: technology + id: ForgeShipWeaponResearchHeavyTorpedo + name: forge-research-technology-shipweapon-heavy-torpedo + entityIcon: WeaponTurretForgeHeavyTorpedo + discipline: ShipArmory + tier: 3 + cost: 32000 + recipeUnlocks: + - WeaponTurretForgeHeavyTorpedoCircuitboard + technologyPrerequisites: + - ForgeShipWeaponResearchTrident + position: -11, 9 + # --- Column -18: mining --- - type: technology From 8f1a7a81ed6a4ae1bc489992a85fb408da88f2c4 Mon Sep 17 00:00:00 2001 From: theg33ka Date: Wed, 1 Jul 2026 14:48:54 +0700 Subject: [PATCH 2/6] added fox3torpedoes --- .../ForgeTorpedoLauncherComponent.cs | 13 +++ .../ShipWeapons/ForgeTorpedoLauncherSystem.cs | 77 ++++++++++++++++++ .../_Mono/FireControl/FireControlSystem.cs | 20 +++-- .../Entities/SpaceArtillery/heavy_torpedo.yml | 48 ++++++++++- .../ShuttleWeapons/gungnir.rsi/meta.json | 15 ++++ .../gungnir.rsi/space_artillery.png | Bin 0 -> 12049 bytes 6 files changed, 163 insertions(+), 10 deletions(-) create mode 100644 Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json create mode 100644 Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png diff --git a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs index 710425a45f0..9f86cb9024d 100644 --- a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs +++ b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs @@ -35,6 +35,19 @@ public sealed partial class ForgeTorpedoLauncherComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public float LaunchAimDistance = 32f; + /// + /// Minimum random delay before the prepared torpedo launch is actually fired. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float LaunchDelayMin = 0f; + + /// + /// Maximum random delay before the prepared torpedo launch is actually fired. + /// This desynchronizes grouped tubes so the payloads do not all elbow each other at once. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float LaunchDelayMax = 0.1f; + /// /// How far from the gunnery cursor the launcher may look for a grid to lock. /// diff --git a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs index 8614c8e8ec9..bada54a4301 100644 --- a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs +++ b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs @@ -1,5 +1,6 @@ using System.Numerics; using Content.Server._Mono.Projectiles.TargetSeeking; +using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Examine; using Content.Shared.Maps; using Content.Shared.Weapons.Ranged.Components; @@ -8,20 +9,26 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; +using Robust.Shared.Random; +using Robust.Shared.Timing; namespace Content.Server._Forge.ShipWeapons; public sealed class ForgeTorpedoLauncherSystem : EntitySystem { [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly GunSystem _gun = default!; [Dependency] private readonly SharedMapSystem _map = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly TargetSeekingSystem _targetSeeking = default!; [Dependency] private readonly TurfSystem _turf = default!; private List> _targetGridScratch = new(); private readonly Dictionary _pendingTargets = new(); + private readonly List _pendingLaunches = new(); public override void Initialize() { @@ -43,6 +50,31 @@ private void OnExamined(EntityUid uid, ForgeTorpedoLauncherComponent component, private void OnShutdown(EntityUid uid, ForgeTorpedoLauncherComponent component, ComponentShutdown args) { _pendingTargets.Remove(uid); + RemoveQueuedLaunches(uid); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + for (var i = _pendingLaunches.Count - 1; i >= 0; i--) + { + var pending = _pendingLaunches[i]; + if (pending.FireTime > _timing.CurTime) + continue; + + _pendingLaunches.RemoveAt(i); + + if (TerminatingOrDeleted(pending.Weapon) || + TerminatingOrDeleted(pending.User) || + !TryComp(pending.Weapon, out var gun)) + { + _pendingTargets.Remove(pending.Weapon); + continue; + } + + _gun.AttemptShots(pending.User, pending.Weapon, gun, pending.FireCoordinates, TimeSpan.FromSeconds(0.2)); + } } private void OnAmmoShot(EntityUid uid, ForgeTorpedoLauncherComponent component, AmmoShotEvent args) @@ -74,6 +106,36 @@ gun.ShootCoordinates is not { } aimCoordinates || } } + public void QueueLaunch( + EntityUid uid, + EntityUid user, + EntityCoordinates fireCoordinates, + ForgeTorpedoLauncherComponent component) + { + RemoveQueuedLaunches(uid); + + var minDelay = MathF.Max(0f, component.LaunchDelayMin); + var maxDelay = MathF.Max(0f, component.LaunchDelayMax); + if (maxDelay < minDelay) + (minDelay, maxDelay) = (maxDelay, minDelay); + + var delay = maxDelay > minDelay + ? _random.NextFloat(minDelay, maxDelay) + : minDelay; + + _pendingLaunches.Add(new PendingLaunch( + uid, + user, + fireCoordinates, + _timing.CurTime + TimeSpan.FromSeconds(delay))); + } + + public void CancelPreparedLaunch(EntityUid uid) + { + _pendingTargets.Remove(uid); + RemoveQueuedLaunches(uid); + } + public Vector2 GetLaunchDirection(TransformComponent xform) { return _transform.GetWorldRotation(xform).ToWorldVec(); @@ -272,4 +334,19 @@ private static float DistanceSquaredToBox(Vector2 point, Box2 box) return dx * dx + dy * dy; } + + private void RemoveQueuedLaunches(EntityUid uid) + { + for (var i = _pendingLaunches.Count - 1; i >= 0; i--) + { + if (_pendingLaunches[i].Weapon == uid) + _pendingLaunches.RemoveAt(i); + } + } + + private readonly record struct PendingLaunch( + EntityUid Weapon, + EntityUid User, + EntityCoordinates FireCoordinates, + TimeSpan FireTime); } diff --git a/Content.Server/_Mono/FireControl/FireControlSystem.cs b/Content.Server/_Mono/FireControl/FireControlSystem.cs index d857a842f3b..ff0d4e2d063 100644 --- a/Content.Server/_Mono/FireControl/FireControlSystem.cs +++ b/Content.Server/_Mono/FireControl/FireControlSystem.cs @@ -538,7 +538,8 @@ public bool AttemptFire(EntityUid weapon, EntityUid user, EntityCoordinates coor // Forge-Change-Start: torpedo launchers are static tubes. The cursor picks a // target grid, but the launch vector comes from the tube's own orientation. - if (_forgeTorpedoLauncherQuery.TryComp(weapon, out var torpedoLauncher)) + var isTorpedoLauncher = _forgeTorpedoLauncherQuery.TryComp(weapon, out var torpedoLauncher); + if (isTorpedoLauncher) { direction = _forgeTorpedoLauncher.GetLaunchDirection(weaponXform); @@ -570,20 +571,27 @@ public bool AttemptFire(EntityUid weapon, EntityUid user, EntityCoordinates coor // Set the cooldown for next firing comp.NextFire = _timing.CurTime + TimeSpan.FromSeconds(comp.FireCooldown); - if (!_forgeTorpedoLauncherQuery.HasComp(weapon) && _fireRotateQuery.HasComp(weapon)) // Forge-Change: torpedo shafts stay static. + if (!isTorpedoLauncher && _fireRotateQuery.HasComp(weapon)) // Forge-Change: torpedo shafts stay static. { var goalAngle = Angle.FromWorldVec(direction); _rotateToFace.TryRotateTo(weapon, goalAngle, 0f, Angle.FromDegrees(1), float.MaxValue, weaponXform); } // Try to get a gun component and fire the weapon - if (_gunQuery.TryComp(weapon, out var gun)) + if (!_gunQuery.TryComp(weapon, out var gun)) { - _gun.AttemptShots(user, weapon, gun, fireCoords, TimeSpan.FromSeconds(0.2)); - return true; + if (isTorpedoLauncher) + _forgeTorpedoLauncher.CancelPreparedLaunch(weapon); + + return false; } - return false; + if (isTorpedoLauncher) + _forgeTorpedoLauncher.QueueLaunch(weapon, user, fireCoords, torpedoLauncher!); + else + _gun.AttemptShots(user, weapon, gun, fireCoords, TimeSpan.FromSeconds(0.2)); + + return true; } /// diff --git a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml index b09ca032efe..0ef61e3762d 100644 --- a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml +++ b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml @@ -10,11 +10,14 @@ - type: StaticPrice price: 18000 - type: Sprite - sprite: _Mono/Objects/ShuttleWeapons/asm220.rsi + sprite: _Forge/Objects/ShuttleWeapons/gungnir.rsi layers: - state: space_artillery + scale: 0.5, 0.5 - type: Appearance - type: ForgeTorpedoLauncher + tileProbeDistance: 1.5 + clearanceRayDistance: 1.75 - type: AmmoCounter - type: Battery maxCharge: 90000 @@ -36,6 +39,17 @@ powerChargeRate: 600 powerUsePassive: 1800 powerUseActive: 0 + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-1,-0.5,1,0.5" + density: 800 + mask: + - MachineMask + layer: + - MachineLayer - type: BatterySelfRecharger autoRecharge: true autoRechargeRate: 250 @@ -52,7 +66,7 @@ shape: Square respectZoom: true rotate: true - bounds: "-1.5,-1.5,1.5,1.5" + bounds: "-1,-0.5,1,0.5" - type: ShipGunType shipType: Missile - type: ShipGunClass @@ -73,11 +87,14 @@ - type: StaticPrice price: 18000 - type: Sprite - sprite: _Mono/Objects/ShuttleWeapons/asm220.rsi + sprite: _Forge/Objects/ShuttleWeapons/gungnir.rsi layers: - state: space_artillery + scale: 0.5, 0.5 - type: Appearance - type: ForgeTorpedoLauncher + tileProbeDistance: 1.5 + clearanceRayDistance: 1.75 - type: AmmoCounter - type: Battery maxCharge: 90000 @@ -99,6 +116,17 @@ powerChargeRate: 600 powerUsePassive: 1800 powerUseActive: 0 + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-1,-0.5,1,0.5" + density: 800 + mask: + - MachineMask + layer: + - MachineLayer - type: BatterySelfRecharger autoRecharge: true autoRechargeRate: 250 @@ -115,7 +143,7 @@ shape: Square respectZoom: true rotate: true - bounds: "-1.5,-1.5,1.5,1.5" + bounds: "-1,-0.5,1,0.5" - type: ShipGunType shipType: Missile - type: ShipGunClass @@ -130,6 +158,18 @@ parent: BaseTorpedo categories: [ HideSpawnMenu ] components: + - type: Fixtures + fixtures: + projectile: + shape: + !type:PhysShapeCircle + radius: 0.3 + density: 1500 + layer: + - WallLayer + mask: + - MachineMask + - BulletImpassable - type: Projectile damage: types: diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json new file mode 100644 index 00000000000..294f1af7fef --- /dev/null +++ b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json @@ -0,0 +1,15 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Provided by Erik for Forge FHT-300 Gungnir heavy torpedo launcher.", + "size": { + "x": 128, + "y": 64 + }, + "states": [ + { + "name": "space_artillery", + "directions": 1 + } + ] +} diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png new file mode 100644 index 0000000000000000000000000000000000000000..99bc37dc9377841d10c5534f3410d5109f478fac GIT binary patch literal 12049 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 literal 0 HcmV?d00001 From 47eb1da1bcf3d8175f9dfd3e05ecec5920e65a08 Mon Sep 17 00:00:00 2001 From: theg33ka Date: Wed, 1 Jul 2026 15:26:59 +0700 Subject: [PATCH 3/6] orientation fix --- .../Entities/SpaceArtillery/heavy_torpedo.yml | 8 ++++---- .../ShuttleWeapons/gungnir.rsi/meta.json | 4 ++-- .../gungnir.rsi/space_artillery.png | Bin 12049 -> 13812 bytes 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml index 0ef61e3762d..1f95fff220b 100644 --- a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml +++ b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml @@ -44,7 +44,7 @@ fix1: shape: !type:PhysShapeAabb - bounds: "-1,-0.5,1,0.5" + bounds: "-0.5,-1,0.5,1" density: 800 mask: - MachineMask @@ -66,7 +66,7 @@ shape: Square respectZoom: true rotate: true - bounds: "-1,-0.5,1,0.5" + bounds: "-0.5,-1,0.5,1" - type: ShipGunType shipType: Missile - type: ShipGunClass @@ -121,7 +121,7 @@ fix1: shape: !type:PhysShapeAabb - bounds: "-1,-0.5,1,0.5" + bounds: "-0.5,-1,0.5,1" density: 800 mask: - MachineMask @@ -143,7 +143,7 @@ shape: Square respectZoom: true rotate: true - bounds: "-1,-0.5,1,0.5" + bounds: "-0.5,-1,0.5,1" - type: ShipGunType shipType: Missile - type: ShipGunClass diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json index 294f1af7fef..657dea7e7e4 100644 --- a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json +++ b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json @@ -3,8 +3,8 @@ "license": "CC-BY-SA-3.0", "copyright": "Provided by Erik for Forge FHT-300 Gungnir heavy torpedo launcher.", "size": { - "x": 128, - "y": 64 + "x": 64, + "y": 128 }, "states": [ { diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png index 99bc37dc9377841d10c5534f3410d5109f478fac..a7a5b08519d19352170fd66454bef76c5fe5a41d 100644 GIT binary patch literal 13812 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 literal 12049 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 From 1fe775cd4387ead6684d419b6d32da44389636c2 Mon Sep 17 00:00:00 2001 From: theg33ka Date: Fri, 10 Jul 2026 16:37:05 +0700 Subject: [PATCH 4/6] retexture --- .../Entities/SpaceArtillery/heavy_torpedo.yml | 16 ++++++---------- .../ShuttleWeapons/gungnir.rsi/meta.json | 2 +- .../gungnir.rsi/space_artillery.png | Bin 13812 -> 19253 bytes 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml index 1f95fff220b..a2ff548aaf8 100644 --- a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml +++ b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml @@ -42,9 +42,8 @@ - type: Fixtures fixtures: fix1: - shape: - !type:PhysShapeAabb - bounds: "-0.5,-1,0.5,1" + shape: !type:PhysShapeAabb + bounds: "-0.5,-1.5,0.5,1.5" density: 800 mask: - MachineMask @@ -119,8 +118,7 @@ - type: Fixtures fixtures: fix1: - shape: - !type:PhysShapeAabb + shape: !type:PhysShapeAabb bounds: "-0.5,-1,0.5,1" density: 800 mask: @@ -161,8 +159,7 @@ - type: Fixtures fixtures: projectile: - shape: - !type:PhysShapeCircle + shape: !type:PhysShapeCircle radius: 0.3 density: 1500 layer: @@ -219,13 +216,12 @@ Blunt: 1 - type: Destructible thresholds: - - trigger: - !type:DamageTrigger + - trigger: !type:DamageTrigger damage: 1200 behaviors: - !type:DoActsBehavior acts: [ "Destruction" ] - - !type:ExplodeBehavior + - !type:ExplodeBehavior "" - !type:PlaySoundBehavior sound: collection: MetalBreak diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json index 657dea7e7e4..789ea2228e9 100644 --- a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json +++ b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json @@ -4,7 +4,7 @@ "copyright": "Provided by Erik for Forge FHT-300 Gungnir heavy torpedo launcher.", "size": { "x": 64, - "y": 128 + "y": 172 }, "states": [ { diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png index a7a5b08519d19352170fd66454bef76c5fe5a41d..f2fd6aa4a230d657a7f7f7ade71cc2a46e34f98b 100644 GIT binary patch literal 19253 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%0DCFo2L@G%yOBg;gd6Zr>NZGzBIJz~ zAu*R9B4CR^H(oQ;H43+&N@l(+jtHh~a+_n=Q-Bm+^hGp0Nl}rfkS$Fl<^wZ?^oGfs z(J|69?4Y+sPL}0tZr-OXM~Q`PJV<2qg5HO?+y_LiVkEFjzUTtuqz6L) zjUieLd4C71Ywq0n*w_6x>J>c>?wa^(i815b*tQ0y1x*Z5e|I-%Wvoh=wry?$(Wuxp()bONC1pV;F0YNUl8mB)Mue zyNkf;MwJ3d;}$$pqGO?U7Cub+Y>f%477?4kU=SXbDk&-JnuV2lu7CJ3MwHAgEOP($ z8gsML49c3(a73#!#p=lu9PI651g;GS5C)8BDDtsbzp1;78}Qj5{v0Y-y!MyhVpI;8 znw<5UWI5^z-+EJe5NAO)6`>&-Mc4-(K1jVK3q&HmqQe?jyfk))5uN!W1g*(3MV93( zEHAULxWL}l9?!k>9QW>QP*x+dTygv3JE$yUG#p|v3`aw(sbhLQM1W~cK@gI#LwE1p z0_&P7UVilz_I8gL_J*81cY=Pej}Wf5@V&Qx5Z!8Ui`LVJSm|Sm@nFOv$Q+9w+Si=1 zsq5P11EnvYHx{X6q@$!SJ_gHs@4Q2&m|#?wfa~jVm0^k(UVe_!)D9`y)WvxZ;TJ+G z=?WYW-r)HMu%NZ^UO{v3#s;;n8I4AahC|+e?*pzp{0Qw%kyL(xHjN4y<2{^d9y?k% zYsvDwplB7*k{aV&%+}T#gJF+ayB(XKS&l#{R$?p3i?6)G-u?l1Z{A64hyz1gTiY?G z7fb-5h$-xL0x)C*GGUQyLyI9eb?y|~n_HCSh{?$*7UmbQ7^<@NQsX;JqBJ?$JV;oG z0ivu4L1s+zK_VhSNw0s*kN?!)K1yV5$@udQYM)^Z_&7Amw*`!2B<8LeTL^Ro?|!|QI=I?l#R8hOmXMlb#&dQ zEGw*qnVBUrUkH+ZWx{uD3fokE>dMvI{o6nOL#AdHndr1Udux4T1+>~N5Efmzii^6g zeIS+i;jtA@L@#lV(Idrz%p@P^J3P{4qN@Z8mfoVIz|_WH&fUL~F5Uk3zw$hHZ*Cxj z(KzNxF!is5}{f&1x&WNeo(#eF~$ZEC&u2BXBqFle}h3~=nY3y)u_Q02?vwK8xj&J zELkQgiWW*`OijEi@-Nnm&uHVF3k&g zEp{qq0#9J0$B6Je$>vGfESi$8-=I}=`0%(u>k<9lG1eZ_Y0oqe+)HMb>KH5Z0$SGov4OQBh_ec+-sy#DB)=QEBQWyB4hRBBHy|*jD|Jsc*%PGqj-_B zEV*#$VPqzlpIc;WdxIA*!s<-PzxY=?1J=kMbWKH~DDS5QjE zl~46Px~@b;Ospdiy!G05xOnMe)PHEQ$u`v)+kiN&H7d){rlzwr!HsJN92_6BFn@)E z!yT}OJa3cd1-;%e*N7B2m%AL(XjlqQe;!Ur?=^HLx^B&`WRVP7!`ltGYsE z8Q;035$zfFyIsyK_*_F)V02AoaQ%&C-4}zZ&j;^)pSigOp1k@f=P#Y5tV-r)mzkei zVR`W+Cr+I8Au+CLB1CbfX=#hbFP6GGiyTtZQg|F8gV9QMGZsvNTc+`*iUz;?Ru^AI z9{h^2ZrP+17+o_pImg`W5{vW8oLD}|^709^u9=ydp{z#i9d0qK1|rT6IPM?uwXgjf z{@{;}kqEx{#h+knbJN8FwPtpH4tv|tUBdeE`Jjbf#jB4!O5Q5?+SmSXw61(Vo?vEXg~6cDne&%8JUVvd zM~o2~qh>wIaboHuWy(*xTP^RwgKVWZri>$~wI@;&zr(WRlmCJsDgodzDPwqQB1U)S_$kHyWgC%G~G;RBj^L2z-R-lxM+@iG&OPt={c;?auNZG7- zEK##fZBB^PjBm9|c|JEUAgsD{fJrnsz^3Ay-ib&;)(0{;p{_3$L3#+ixxPhRS4brh zfdlaNqR0#PNHQ>6@j=JPmoXb)X{I)aFjv5LT{|P}Yis;hsJBsG1)9jl5hzbweUk6I z^_F9re3(5Rk2h-{cmZD`Os6x+>guX*nh4BM!%_(;SX`Rp_^8L}v!^fthIp1*Wf^5z zI-^TNy@jr~PcDFkvK+Ftu|=zBqjklgKM2U1{;-G2ngUZ39!KI^a__AevG-reTpJy|hix9@&TuiJ||9{Ibmy8q;%q9ml2K1fdEa;1m1Hj$_RgZFp$SXo_m{GVUE z+1Xhhdgwf_e&$6EkM|f12R!@fm-*FS`wc$6_JMcX&T|BE7vU1SdC_hpKnT}8iiN7G zSYKO@G*!UuKlt9e^ajUFO-?f-=lJ#;Z?dqsJm$`9pvK0iESD6CNH0lU1p+0k!x+hd z3zGKtj}XAr>?DK!zh%aaeq-7BCVC2FsHu0Q8Yi?eTxA192XaGZF+ss0j0>CACrP2`_7AD55&eNvEx9yviq-i` z{N{i0Uo$~8|hBk%~wZwyvOQ`BG*m1V4L-Qu{r$K32ZmoHsqW@-sJst5E22OJ+BGP^Lx zmwx0k{Jp>PxB2ke_o=Ho!T0WBu2s!O>e3n;ilfiBcCzajjQ{BG1^{+u-pl&oeW%fUXULQI9;!k?nkvnW+V~)*WMd z`}RKHd;2DjKlUu|UHdkfDjJlQh*e~11hm^NPM%)n+pm8Qqix~}8$K{Zk&r}-W0pT4 zM;pW45M4HPOa7swj(8iAj>?Ij?LKLJ;}##^c$X`WTxD;6oh)-CZ(Uce?l=IF;i&Yw zD5=UC9=Ko-JC}W}JyYXaY+PCl&Rsgk`n@%(s%{=ONsYx)_~d%{86+ac0*TuA=`mV2 z*j+ReyPBd3Z-|Yxs91s83{NrEa*H9{lPI$KlhX$VbRc3=Pq7g z{r)E3dE+fkoIDXraMOHXeEe9PA(ESJ_=m_KOA+0hul9)rn4y9-I!|Liu^7U->Vv=g z(2mP#s)h!URb4SEhb}WTs`!uo$8Yl0fBJgt7mT38U(7KuIYr)Petw=8UwM(KnW+Q} zS$wMWMr|4qw$L^m1K8sm)HO5O^yyi zdabc;)>r#*R5LnpFrliLXX+Uv+IGJPtU(TG0S9YZ4V| z@VvE_Z~Vm{lc_ucI}k{1>n6b<1y`0dPs|R+{BR8A$2h;HBCGk7Xx_kD>bjFxG`2sEz3XskuLx2tFB9ov~F00oSyIH@kTKOLrragjZ&g~HaUn+R41E~=Lrms z?#o7IM~bFMqD{?e(dWlkVNR7!GDP#B097cU7!xT6;C|yP88h~Pmh|m>n5MT~2#Exq z`Kd=Z^MwlyluUe%Nw~B?pSvp1aRg_r1=F;_jXhnWM&Y-yeK+`eTuGitdVB*ec;?}Z z|L&LCoHlEIvRrfh0DFx!apBSm(z(@)6Kyv)M5&Cb_BbF+i4?-X=_fE}o{o%6z|n!Y zXe8NBj}r}eX`a>pJSuS@ed7R&G}dW$F+qRM-4OwpFSSA~Ofh?TnOqMdwus2lZ52~p~8j>fegFkLJfndHBuz{m9i6_lGaf#Wdc+K0&4&efc7o+v3DpX zOvJbw3}DD&ql=71jlz|~j7B45K1n8puY~m*5aN%3IOCc+8=*~w5SETo&b|7;DGpT~ z42M{uuzMfD$e`5Z_{zrkTSQ>u#4~_N>j=&Sg@px*TOA`p8eo*P$Gah^#=p#0ko&=h z)>>*~X(=F#_lvfrxi@PajW3ewbvMmIGFZDy8v}lzla!g8D;&byeq|7w+f>H_t=o+O zd%)P^-HjAUFyqJR1&Eu>i|}PMAq|$YK233CP=(}C;%DlB-i$zK4WnZsvJedjBPL8u zvl zCfGkD)rDvtw0W-`lfEb|LeSDB2k-4*)ygN5sp0x@GNuR@b)&%lkKZ3s)|1q_VV0y) zxl0%effX75_-le+|Fg8$KkXxE{IwiQb3GXQH>GP9L6&9FFAE&q72oJrIQ2Ho@0@x> z`ymy-_eRaj|9y{jGfOj9CVaj?c*!(oTzsX<_^00iBl0)|LQ3gsg@e&D){?cC$tMe6 z&>X;th&vOPCR$sU1+q!x7d?i5k`SxM=sxBBX+%lH_M6yH_q7J@H;lqnW8g2&Gz;&A_67REJQjI!~{oXe6mDRn-VFS znWEBKgAC;+!20GL);4atS)YMm6bS@2V1;RTzo?_00FC)Q6Cd`$osJKmhOWNINhEmz zg8K{b)>?YKF1vd>oV|F$L0XZjVFRulh_iqz{TIr~=KYP^N%55>3u)&tHt!ez(XV2) z;k~y%^egEHkNARw(EJ?v{1pF_BnyR%15~6E5!^J35@5WD;+hQTY~li6n-J7zW#t4X zPkx!borCcfpTtl{`{TRGtj`B3m2vUhqYh-%BR50cK~DE@+GyT>^Bre|eH^c(8?8^I zolHYxdz;`y+EQmQszCKLu+Z7a@kUG_F%LZZPHq6TDf~zC2!pmKd7!eUg5E z@ZU;id}>*8ZF@vnbg;*V$U?Q_M7L1cC50PyT-DXsnA%L`iG>eD#klovdWGVT#<)b0 zM3f?_?YA^V6pa`^P|;zV_e8cS*v%l3egIpP3K4RHj>h}`M#(@o1zyrUjADL%#!*LB z&}z5&_~Re&$U|3MJzW6r9$&kfyzv}=s))gJ1UFZefq!cT8I6U69;Clx=j2gvWDG2}%-k!NGD)p~`o7FXzGnoLg272rIK@lw@r6e3opOQ}4L zu<>_|YlKVZ9^v$IFYG++ABpX9{q z=}0fxw0qQxW;BKYZAEC9#^;uE7tiypZ@k9l)(-7XJ64E9n;?YmL={aWClX1BQKM+= zP*O5xLnTPq8l~LaLLVTxAW3rm>}9T9|32kt#PswuOAE^`r`R7Ixi@ZEUV8P1=?w-bqhgcNr3CSx>3XUeZ)!~2Oef|DY)ym)1Iu-IrPva#kr zG(?YQi^G=-go0s9-{ZH=q^cpKv2AtXk-c>(xVxhk~TjRB|zUD_z64S0zXQ2V+2+Z$_aZETR`dE8lJG_7_U zYc*v#H&ts=B0Ibl5xG;-`Q5Z_yhJSX^4*{+;_C zr6pCMX?tG~eUh;n#&YxeOJ!O>2VfZ=-v4%a zb%mqDBi8S((Q36=Se~aGl@26%uCmjaV0LcWzPFL$t9;l~@vwr*VFyr~E_v3{t=f zLI{^zNQ$c>7VraA(wal-tE;DHrYZ6k>uYN)t}L>@d%)!M1nr4-bUL1P54DZ%p7JdBNBuRVt~T1g zw|VUGrYS!-Iej##6tyuR6jkYxrrI=lyyX7;6&iq%)<%)A$e~mwa08@^)VTTNE4{iO zsGv2|vr{oR3WqWVLMAMD!x{x6I6kU-Y>0{!BF++NZq&s%QVO4AGtuRxcs~wDO>Vj& zNM#flT6G_7NM>r0#`_mOh5XWzYx#rf#_vy_x{KxodQo+>CWMS5euYR_h}7WzbrKMKWit`h@3;qhMbV03sFDe5oa|(ziW2{CV~EyBM4Tk; zsr4|5mj@`Yv~(sQ#z3aVYbI(ENt+}PYbN*vqx%25049oPxRG$;WZ==mO4r&KNZ1Eu zt#MsV!o$YDO*|rxhQk*jB2~??orHk|X(fqmfKtR&A{JAm`W>zv=AS=Un)}x-K)m&E z;UqY5%!@l4)QK-KX(19SD$-ivXNiFf)m)BVr;!%mp(_tDF*QNf%A05R?6OGjZVc8o zCez@XEJO8Zs6F;TEd=Y@XPG{+0O5vR<#nSHP5#{rTFAML!+-?v2nelrCK$4WT8TOt z5}@wAr%#`zd(@*GmR`)8&xl9l`3N-3Ds0pQSCQfqoQ35Q`>m9PYz0Lma9{pb5iPR@b(wjZE*rqT! z{3Oiv_-iUdgOLm|Lc=av78d7t?X|Zkih^f9{Zyp2Y&2Rn8o%&SsafXcmzbEGjD{)Tf8lQ`&CN+) zu+R*_@aeE%41)+JmOCs%IjVU2nJ2k(^Df{0&f7fw>{ERA+ux59C7S(j7EubB)ciFz zveTIWYsvDA{ex|4T`?*L7*nIIrj>UPg`_(;B%7IBq{s@s@FQOVDLB~MM@Yf`?k+d3 zU*p=x-{b7*E97Aakw|a7xvltcVYd>H5*8y=hgcI1V6c(oxOM9uCstS3+1+J&YLXA% z`zYF>fc6485=1fnF6y}F6#XEUZf~DfF-co?ICJWfn;DW9v|1geCMS98yWb!axYMO? z-@47#<~lQTb5vE0sVmN%e~A6Jx7gj=;MB?U@%c^cBNnkTGuVj`2*vs}5$cJ;Tydi1 zPlumfxOkTPckk0GG8R{sSYBS@&DY-Y4H1b11?!(oybA_6oOx2~8ibpPc5-zQi{S8Z zkE$ve9q!O>PjYaOxeSp~&Zs^7$OX<_yom9W;=0}A=3=(li9k<9(T~&Mn*u2JtPLg| z^W#236uxrX2sf7NwQs&b(aKppxk|s=gv<6nS0*DAqVV(F89I_Khq^!U`q2 z+q}8K@}b+q3O@YcI-8r@9PA(R%yUo2DK(JP5+txVQ0Xx)@vc*PT0T~a#kcwMl(mV{ zmuYKh`LTJ%7&jWjT9oj8b&0MTt^MPe_>jQ>hD2$^?Uo34t?w5$A-9KURK!cnv(H~e z2*YdNe2YBKdHZ|s`UbJo2*z2yu^-t2MmG{F64i3oPR<({^amg@}9bF4AE@vS!_coBXx2m?@ra03&hKO-r#F^zAr?(FnH zqNoSwjK-S;cgTwLt|%=p4Z2Gcg9EiO2qm#~=wj!H(uGOCUgO+*@m z*XZUPQY9t#?yfO8HNl0;7x>KQKIf;#S^9%s)60-7Uc8zh5+hmjpn;zs&(1^<5AGMjMHrCg9=J{v2ck2$_qaMT2eQ#Srv9pK=sW{+d9E&6c zbyfKq0zs!e5eqh_r)T)iYj5!BmtJIH=_JP1+`RQZQ!P^%PngG9?)dDtFdU0A-;W zy9rp5xCB=x*vMzS8pNC@HnZ#QA_+K{1aECO% zO)QfCNMj9Iq_dM5h4pIoVw{}4ax`%!0s$^w#g?o3_5K?+e+^Emm-TPd9 z_A2XZn+OcMJ4al3^a^)w-$VHG%=FM5vKlHCVu&l8&Tp=7@X#XPdIn%78vxrE%1d+)>w*m&R{TX z)XCpZS~jahI6qjC6?vk1#I(JuVUS79lP7w-yky}`p~5=2t-#rd5b;^)4Z2KpI-EGM z$nx?MO63SCD6*W>0hb@W!shxmMW-ES5eJ*Ia&no$V8}b)f19VD zeHyI|2M34rj*fZ$<>&bL!<+O6eRQq4{?Sd&oj(%;8zCi|+iPrW-ljhs@zBM`kXeSU zh6y|EszYmk=AaDcn+6Wv9k=IHAkSPERR}BbqbWUZMMy!b-C|~bn%1b`@bHN4ai4al ziUX3QQY>{U5o@8Ruosze^vlAoFK$s|h0>1D@H-jXuHci7} zIx@>z?JKp9dHby&V69{@=rS1g84ibpqk5#w7>x#QzL$_(diXL{f~^J1Csr5^hLIx_ zLQ?G?MT?&ruRLpU_tt%+lq@bTb9i*b?(PoV<9)0@)oRf1vv;`7aM&kP8PhX!?Cx*V z%3FSDi$RIZpOk6GLiSL!VXY-|0LX*4X^-Q8ohoaN~FklI=f4tJQDUTBg%ftDMKS^R;E`11c|aC#s= zTzA!Q(C6~QPx9g`&x0_u+im{Y|MXidE@(@S}KO9hwO8>aYU#li%HOUBvuR-{cGiz!D@F3Um)#f08GzJBV|T^c+B|=r`g{< zqIcAzcYH)ujaXhhMX!Gt)j4&O!ab%->}peU_TuT7Rl$>sp<)!=sm;nKMe528SU7j_ zJW4uC8zAQT+WG^bv9m2Q-GM|O)1Zk2j0b2Q2+tU_d3zJsrlZ3{o_Y2;?%&(;lIss^ zv99_xjL>N65XK9@Wx)FDcik90lO!D4t&W@BgX0X9lz!(WQia0{h-Y}X#Y>D$ERbr_ zTr%Mk1G_7%OKp+xDyba-~lu$B5WwN&AW5Zy zXh6eHr2rike5{&XMm0_oI4;pEV<`Z}ST0^V>o1U`!Yl}(nCMJK*HpA}fBtehF(M66 z{P*6dl8EmZd6MXUIHTafB4+{(9xf7rjK72@Zmo5(Kupkt?6EMh2qRGJBKdei`=gYS zqrwl_DB%H;y;a)gkQPP^d0{LTLs zB_vbRGj4(dI`VI+bq{KovTKO~HyRobcW55430*~kOoL5G!IOw%zHWSUm${`yj`t3! zv^(lY*Odc#nIDuPC7p>W+N}=lcH0evDzg8ts&n~~m-~duDcKc4pV>?AqXs z9oxYucAP^1<-mbRi4X@k!jU^dj`DvXf$}GCLLA_RVu%zW0}?pkSbjg(kKOERc6MI< ztmaVFHM{4QMw;%b@9*{feZNsf5Rm67LP+0?%!|wdo>1seGoFoTL~Z(u%g%XbuE}RF zu^|YgzjOXH)a_|kZf99SS=J@%oWfF%uKYbYQrFkjpAyPtanfT(eQLXleeygbRGLRm z?$B(+BuPd|ju46@84(DHl8QXH|1FS$pxx|MN+~}2_$Lew_8A?HkXmu~)@@Fm`ZnEu zn>dP@CMm6j2CtsJrZk3bZ-Mc_m~wut-4w=+KisC7HD#JR*kncO0n|I$x&FaXEuzZD ze@Dm&=FD@OC<%u#HVVa!CgbshUVjl|N)8W(1R@|SGPG{+;>ANwuAHI~H=Jf7Jl}YL zA^?db%QCh$cR6)>nRDmP^YZZqi@iQoX~@zNQ3{&PCWnWI#5(5A?XP+3>?N@5oFhnI z1Nq#lw=4{W$r%oI>GxNB91a4TU`2842P9N=O;V%uoW>Lg;U#vDQf%@f<>|8roLF8Z zNmF-1Bmt1jrsPRVtQ)l3Jr4Hw(2+(dmsKhef)wOMNpG>s!NG{b@euE%>Qo^`C{R+O zb%Y27=ijXQ@xl@ES!G!-IYQ(rN%!QiN!?0EM%sdHU$3f9uD{MoxY|)FB9X zx$)S4F>A418y?sWOqQi|J3S9rT8GrhqEM0|%h6gR2>e*gIJu0#`2pKV@mNXyJqXVN^SGKNSu zm?aa^ETPqETfK6r*xG){-u@;ZeE&mMmRHI192IKoYON%L!GQ62z-T&jJIi%qWlx-O z5u+Z^S{yOQb`F)5zpML#f%odH$;SQ&I!T-(y;BGTairPYeZ}x#NUz@~NoG`4Kw4T^ zYvWkjB9I^iVW6Gy3g{^IkQXI#%0F(PTCy)XJNg)Lw;+ zMuV)#kbxjn+FvQFQYVfiH^xT-V~lf(uOAu0P!muQHzV>iA z&(m|)HL6Pg#cD{YBX?C*2vZq~ykKo@#TqCdS!R&+0+Q>}M3J4-1Cyus?pHLpBbnvy^M;rE16k>v@}`GVFQgR(MQe&>Dm_XiLd@}i)u zBs)9X^cVY>+)z`^YXephLNc8qPs|CMpa11gwi8@rh(My1CNByW7CMY4Ln@3fhD=#c zrz%WPk!CaBbL{n(*xBC1R3&+lB85T?$9r_EB~G1QW#x^Ny!ZZPy4^0f{_{UR{_)S4 zP9`L2O0%W8_Q|jK?QcG#v(Q5Xu>P$Jj39GcK7z|3@jV%t*x4WQziomXr;f6P*U1r>(0S}h(vx#b%< zRj1kG*PmWvG#)`9_~+lh;@+K`T)z4}s7fweJWFXxzP@>nqAXbK_ec|KVW&gMlc)Dt zIk83@H4tvi=Jn<#I*fS!;x39jlKd4ZH+oqkc|IiU_I%Zl&3bBXQEEkYf!zq@OF$6Wv7 z;iKEUec=kNcAJOy?($;mL0zhNP_J~@K!>qKX~)2nQeg^1r@cg0q!dNUWIAGf{USwf zWh_@#dc+NljvMrb&zN?X5YZB^w_dTmHDo#&p|nCf&%&y*?X}T(gz}qQna$3Ec|TGK zX}`9VtiQR=O0U5*Nx1pdea@c0#KHc6EK3l9peQoO5HY05j6evqj*qktDuj?c-@H$n c&HT9Z{|5T4m<=Q4EdT%j07*qoM6N<$g4SWE#Q*>R literal 13812 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 From 0ff0244193f054d2a5a96999f0135fc047f8c039 Mon Sep 17 00:00:00 2001 From: theg33ka Date: Fri, 10 Jul 2026 19:05:10 +0700 Subject: [PATCH 5/6] small fixes --- .../Entities/SpaceArtillery/heavy_torpedo.yml | 9 ++++----- .../ShuttleWeapons/gungnir.rsi/meta.json | 6 +++--- .../gungnir.rsi/space_artillery.png | Bin 19253 -> 5515 bytes 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml index a2ff548aaf8..c189b6abe32 100644 --- a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml +++ b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml @@ -1,12 +1,11 @@ - type: entity id: WeaponTurretForgeHeavyTorpedo - name: FHT-300 "Gungnir" heavy torpedo launcher + name: FHT-300 "Gungnir" тяжелая пусковая установка suffix: For mapping parent: - BallisticArtilleryMapped - BallisticArtilleryTier4HP - description: A heavy Forge torpedo launcher that can fire from the hull without direct target line of sight. The muzzle still needs open vacuum; firing into your own plating is a bold plan, but why? - components: + description: Тяжёлая пусковая установка для таких-же тяжёлых ракет. Может вести огонь без прямой видимости цели. - type: StaticPrice price: 18000 - type: Sprite @@ -76,12 +75,12 @@ - type: entity id: WeaponTurretForgeHeavyTorpedoPortable - name: FHT-300 "Gungnir" heavy torpedo launcher + name: FHT-300 "Гунгир" тяжёлая пусковая установка suffix: DO NOT MAP parent: - BallisticArtillery - BallisticArtilleryTier4HP - description: A heavy Forge torpedo launcher that can fire from the hull without direct target line of sight. The muzzle still needs open vacuum; firing into your own plating is a bold plan, but why? + description: Тяжёлая пусковая установка для таких-же тяжёлых ракет. Может вести огонь без прямой видимости цели. components: - type: StaticPrice price: 18000 diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json index 789ea2228e9..d5d633571dd 100644 --- a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json +++ b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/meta.json @@ -1,10 +1,10 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Provided by Erik for Forge FHT-300 Gungnir heavy torpedo launcher.", + "copyright": "theg33ka for Forge-station", "size": { - "x": 64, - "y": 172 + "x": 32, + "y": 86 }, "states": [ { diff --git a/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png b/Resources/Textures/_Forge/Objects/ShuttleWeapons/gungnir.rsi/space_artillery.png index f2fd6aa4a230d657a7f7f7ade71cc2a46e34f98b..b7cc45e2eedfdf364da83c4e1fd6977f8f96b44a 100644 GIT binary patch literal 5515 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°l&>SD-{?ex$9v(3?ROi~|XV~3+T-BU1 zRY?+ayxSws3$m0NHGv0w{`nUwaWagAbui-biV-7R zzIw5$TJ`!c07FAVgifra*;)lo30C3#k=Q#%vT4M`QC{e>s?w}MLrAQxrmj)UGAu1V zK-C3l)g~lXn3x#n{N-~MVwJM!ak&L8Uveqg5S1kZBlhfU?*yuDz&oYcoCu>mn*>YN zlDg(aMq(3kms3j`WJRCTvlk)G2tdPIRdFE^LzeY$P9weYgaLjqf11={YZpvEJTl7i z%0ieI8Ks|fQ14078qyq@)HmMvS$h2=KK}3?XU|^%g$ECo*l%rd<?`1msE#mS|G8H|{vTSndF%I8@`L~Y N002ovPDHLkV1fcRz>fd` literal 19253 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%0DCFo2L@G%yOBg;gd6Zr>NZGzBIJz~ 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 From 4e891b87af6c55fd9987d1fd1b758e511166521b Mon Sep 17 00:00:00 2001 From: theg33ka Date: Sat, 11 Jul 2026 00:40:21 +0700 Subject: [PATCH 6/6] fixes --- .../TargetSeekingSystem.Forge.cs | 15 ++ .../ForgeTorpedoLauncherComponent.cs | 21 +- .../ShipWeapons/ForgeTorpedoLauncherSystem.cs | 212 +++++++++++------- .../_Mono/FireControl/FireControlSystem.cs | 42 ++-- .../TargetSeeking/TargetSeekingSystem.cs | 23 +- .../Circuitboards/Machine/ship_weapons.yml | 2 +- .../Entities/SpaceArtillery/heavy_torpedo.yml | 94 ++------ 7 files changed, 177 insertions(+), 232 deletions(-) create mode 100644 Content.Server/_Forge/Projectiles/TargetSeeking/TargetSeekingSystem.Forge.cs diff --git a/Content.Server/_Forge/Projectiles/TargetSeeking/TargetSeekingSystem.Forge.cs b/Content.Server/_Forge/Projectiles/TargetSeeking/TargetSeekingSystem.Forge.cs new file mode 100644 index 00000000000..3920aaf4e44 --- /dev/null +++ b/Content.Server/_Forge/Projectiles/TargetSeeking/TargetSeekingSystem.Forge.cs @@ -0,0 +1,15 @@ +using System.Numerics; +using Robust.Shared.Map.Components; + +namespace Content.Server._Mono.Projectiles.TargetSeeking; + +public sealed partial class TargetSeekingSystem +{ + private Vector2 GetTargetWorldPosition(EntityUid target, TransformComponent xform) + { + if (TryComp(target, out var grid)) + return Vector2.Transform(grid.LocalAABB.Center, _transform.GetWorldMatrix(xform)); + + return _transform.GetWorldPosition(xform); + } +} diff --git a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs index 9f86cb9024d..ae716f561a7 100644 --- a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs +++ b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherComponent.cs @@ -3,28 +3,21 @@ namespace Content.Server._Forge.ShipWeapons; /// -/// Marks a ship weapon as a torpedo launcher that only needs a clear muzzle lane -/// instead of full line of sight to the gunnery cursor. +/// Marks a static ship launcher that uses its own facing for launch direction and +/// the gunnery cursor only for target-grid selection. /// [RegisterComponent] public sealed partial class ForgeTorpedoLauncherComponent : Component { /// /// Distance from the launcher center used to sample the tile in front of the muzzle. - /// That tile must be empty/space, because torpedoes prefer vacuum over chewing the hull. /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float TileProbeDistance = 1f; - /// - /// Short physics ray distance used to catch hard blockers immediately in front of the muzzle. - /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float ClearanceRayDistance = 1.25f; - /// - /// Collision mask for the short muzzle clearance ray. - /// [DataField, ViewVariables(VVAccess.ReadWrite)] public int ClearanceCollisionMask = (int) (CollisionGroup.Opaque | CollisionGroup.Impassable); @@ -41,22 +34,14 @@ public sealed partial class ForgeTorpedoLauncherComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public float LaunchDelayMin = 0f; - /// - /// Maximum random delay before the prepared torpedo launch is actually fired. - /// This desynchronizes grouped tubes so the payloads do not all elbow each other at once. - /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float LaunchDelayMax = 0.1f; - /// - /// How far from the gunnery cursor the launcher may look for a grid to lock. - /// [DataField, ViewVariables(VVAccess.ReadWrite)] public float TargetSearchRadius = 48f; /// - /// Minimum amount of tiles a grid needs to be considered a torpedo target. - /// This keeps expensive fireworks from chasing loose scrap, because why would it. + /// Minimum tile count for a grid to be considered a valid torpedo target. /// [DataField, ViewVariables(VVAccess.ReadWrite)] public int MinTargetTiles = 25; diff --git a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs index bada54a4301..8f0125da1d1 100644 --- a/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs +++ b/Content.Server/_Forge/ShipWeapons/ForgeTorpedoLauncherSystem.cs @@ -1,5 +1,7 @@ using System.Numerics; +using Content.Server._Mono.FireControl; using Content.Server._Mono.Projectiles.TargetSeeking; +using Content.Server.Power.EntitySystems; using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Examine; using Content.Shared.Maps; @@ -16,9 +18,12 @@ namespace Content.Server._Forge.ShipWeapons; public sealed class ForgeTorpedoLauncherSystem : EntitySystem { + private static readonly TimeSpan ShotResultTimeout = TimeSpan.FromSeconds(0.5); + [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly GunSystem _gun = default!; + [Dependency] private readonly PowerReceiverSystem _power = default!; [Dependency] private readonly SharedMapSystem _map = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly IRobustRandom _random = default!; @@ -26,9 +31,9 @@ public sealed class ForgeTorpedoLauncherSystem : EntitySystem [Dependency] private readonly TargetSeekingSystem _targetSeeking = default!; [Dependency] private readonly TurfSystem _turf = default!; - private List> _targetGridScratch = new(); - private readonly Dictionary _pendingTargets = new(); - private readonly List _pendingLaunches = new(); + private readonly List> _targetGridScratch = new(); + private readonly Dictionary _pendingLaunches = new(); + private readonly List _pendingLaunchScratch = new(); public override void Initialize() { @@ -36,6 +41,7 @@ public override void Initialize() SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnAmmoShot); + SubscribeLocalEvent(OnEmptyShot); SubscribeLocalEvent(OnShutdown); } @@ -49,91 +55,85 @@ private void OnExamined(EntityUid uid, ForgeTorpedoLauncherComponent component, private void OnShutdown(EntityUid uid, ForgeTorpedoLauncherComponent component, ComponentShutdown args) { - _pendingTargets.Remove(uid); - RemoveQueuedLaunches(uid); + CancelPreparedLaunch(uid); } public override void Update(float frameTime) { base.Update(frameTime); - for (var i = _pendingLaunches.Count - 1; i >= 0; i--) + _pendingLaunchScratch.Clear(); + _pendingLaunchScratch.AddRange(_pendingLaunches.Keys); + + foreach (var weapon in _pendingLaunchScratch) { - var pending = _pendingLaunches[i]; - if (pending.FireTime > _timing.CurTime) + if (!_pendingLaunches.TryGetValue(weapon, out var pending)) continue; - _pendingLaunches.RemoveAt(i); + if (pending.Fired) + { + if (pending.ExpireTime <= _timing.CurTime) + _pendingLaunches.Remove(weapon); - if (TerminatingOrDeleted(pending.Weapon) || - TerminatingOrDeleted(pending.User) || - !TryComp(pending.Weapon, out var gun)) + continue; + } + + if (pending.FireTime > _timing.CurTime) + continue; + + if (!TryGetLaunchState(pending, out var component, out var xform, out var gun) || + TerminatingOrDeleted(pending.TargetGrid) || + !CanFireNow(pending.Weapon, gun, pending.NoServer) || + !CanLaunch(pending.Weapon, GetLaunchDirection(xform), component, xform)) { - _pendingTargets.Remove(pending.Weapon); + _pendingLaunches.Remove(weapon); continue; } + _pendingLaunches[weapon] = pending with + { + Fired = true, + ExpireTime = _timing.CurTime + ShotResultTimeout, + }; + _gun.AttemptShots(pending.User, pending.Weapon, gun, pending.FireCoordinates, TimeSpan.FromSeconds(0.2)); } + + _pendingLaunchScratch.Clear(); } private void OnAmmoShot(EntityUid uid, ForgeTorpedoLauncherComponent component, AmmoShotEvent args) { - if (args.FiredProjectiles.Count == 0) + if (!_pendingLaunches.Remove(uid, out var pending) || + !pending.Fired || + args.FiredProjectiles.Count == 0 || + TerminatingOrDeleted(pending.TargetGrid)) { return; } - if (!_pendingTargets.Remove(uid, out var targetGrid)) - { - if (!TryComp(uid, out var gun) || - gun.ShootCoordinates is not { } aimCoordinates || - !TryFindTargetGrid(uid, aimCoordinates, component, Transform(uid), out targetGrid)) - { - return; - } - } - - if (!Exists(targetGrid)) - return; - foreach (var projectile in args.FiredProjectiles) { if (!TryComp(projectile, out var seeking)) continue; - _targetSeeking.SetSeekerTarget((projectile, seeking), targetGrid, Transform(projectile)); + _targetSeeking.SetSeekerTarget((projectile, seeking), pending.TargetGrid, Transform(projectile)); } } - public void QueueLaunch( - EntityUid uid, - EntityUid user, - EntityCoordinates fireCoordinates, - ForgeTorpedoLauncherComponent component) + private void OnEmptyShot(EntityUid uid, ForgeTorpedoLauncherComponent component, ref OnEmptyGunShotEvent args) { - RemoveQueuedLaunches(uid); - - var minDelay = MathF.Max(0f, component.LaunchDelayMin); - var maxDelay = MathF.Max(0f, component.LaunchDelayMax); - if (maxDelay < minDelay) - (minDelay, maxDelay) = (maxDelay, minDelay); - - var delay = maxDelay > minDelay - ? _random.NextFloat(minDelay, maxDelay) - : minDelay; + CancelPreparedLaunch(uid); + } - _pendingLaunches.Add(new PendingLaunch( - uid, - user, - fireCoordinates, - _timing.CurTime + TimeSpan.FromSeconds(delay))); + public bool HasPendingLaunch(EntityUid uid) + { + return _pendingLaunches.ContainsKey(uid); } public void CancelPreparedLaunch(EntityUid uid) { - _pendingTargets.Remove(uid); - RemoveQueuedLaunches(uid); + _pendingLaunches.Remove(uid); } public Vector2 GetLaunchDirection(TransformComponent xform) @@ -141,19 +141,38 @@ public Vector2 GetLaunchDirection(TransformComponent xform) return _transform.GetWorldRotation(xform).ToWorldVec(); } - public bool TryPrepareLaunch( + public bool TryQueueLaunch( EntityUid uid, + EntityUid user, EntityCoordinates aimCoordinates, Vector2 launchDirection, - ForgeTorpedoLauncherComponent? component, - TransformComponent? xform, - out EntityCoordinates launchCoordinates) + ForgeTorpedoLauncherComponent component, + TransformComponent xform, + bool noServer) { - launchCoordinates = default; - _pendingTargets.Remove(uid); - - if (!Resolve(uid, ref component, ref xform)) + if (_pendingLaunches.ContainsKey(uid) || + !TryComp(uid, out var gun) || + !CanFireNow(uid, gun, noServer) || + !TryBuildPendingLaunch(uid, user, aimCoordinates, launchDirection, component, xform, noServer, out var pending)) + { return false; + } + + _pendingLaunches[uid] = pending; + return true; + } + + private bool TryBuildPendingLaunch( + EntityUid uid, + EntityUid user, + EntityCoordinates aimCoordinates, + Vector2 launchDirection, + ForgeTorpedoLauncherComponent component, + TransformComponent xform, + bool noServer, + out PendingLaunch pending) + { + pending = default; if (launchDirection.LengthSquared() <= 0.0001f) return false; @@ -171,8 +190,23 @@ public bool TryPrepareLaunch( launcherCoords.Position + launchDirection * component.LaunchAimDistance, launcherCoords.MapId); - launchCoordinates = _transform.ToCoordinates((uid, xform), launchMapCoordinates); - _pendingTargets[uid] = targetGrid; + var minDelay = MathF.Max(0f, component.LaunchDelayMin); + var maxDelay = MathF.Max(0f, component.LaunchDelayMax); + if (maxDelay < minDelay) + (minDelay, maxDelay) = (maxDelay, minDelay); + + var delay = maxDelay > minDelay + ? _random.NextFloat(minDelay, maxDelay) + : minDelay; + + pending = new PendingLaunch( + uid, + user, + _transform.ToCoordinates((uid, xform), launchMapCoordinates), + targetGrid, + _timing.CurTime + TimeSpan.FromSeconds(delay), + noServer); + return true; } @@ -194,7 +228,7 @@ public bool CanLaunch( worldDirection = Vector2.Normalize(worldDirection); return HasSpaceAhead(gridUid, grid, xform, worldDirection, component) && - HasClearMuzzleRay(uid, gridUid, xform, worldDirection, component); + HasClearMuzzleRay(uid, xform, worldDirection, component); } public bool TryFindTargetGrid( @@ -254,6 +288,33 @@ public bool TryFindTargetGrid( return targetGrid != default; } + private bool TryGetLaunchState( + PendingLaunch pending, + out ForgeTorpedoLauncherComponent component, + out TransformComponent xform, + out GunComponent gun) + { + component = default!; + xform = default!; + gun = default!; + + return !TerminatingOrDeleted(pending.Weapon) && + !TerminatingOrDeleted(pending.User) && + TryComp(pending.Weapon, out component) && + TryComp(pending.Weapon, out xform) && + TryComp(pending.Weapon, out gun); + } + + private bool CanFireNow(EntityUid weapon, GunComponent gun, bool noServer) + { + if (!_power.IsPowered(weapon) || !_gun.CanShoot(gun)) + return false; + + return noServer || + TryComp(weapon, out var fireControllable) && + fireControllable.ControllingServer != null; + } + private bool HasSpaceAhead( EntityUid gridUid, MapGridComponent grid, @@ -274,7 +335,6 @@ private bool HasSpaceAhead( private bool HasClearMuzzleRay( EntityUid uid, - EntityUid gridUid, TransformComponent launcherXform, Vector2 worldDirection, ForgeTorpedoLauncherComponent component) @@ -289,7 +349,7 @@ private bool HasClearMuzzleRay( launcherXform.MapID, ray, uid, - IgnoreNonMuzzleBlockers, + (entity, source) => entity == source, component.ClearanceRayDistance, returnOnFirstHit: true)) { @@ -297,17 +357,6 @@ private bool HasClearMuzzleRay( } return true; - - bool IgnoreNonMuzzleBlockers(EntityUid entity, EntityUid source) - { - if (entity == source) - return true; - - if (!TryComp(entity, out var otherXform)) - return false; - - return otherXform.GridUid != gridUid; - } } private bool HasEnoughTiles(EntityUid gridUid, MapGridComponent grid, int minimumTiles) @@ -335,18 +384,13 @@ private static float DistanceSquaredToBox(Vector2 point, Box2 box) return dx * dx + dy * dy; } - private void RemoveQueuedLaunches(EntityUid uid) - { - for (var i = _pendingLaunches.Count - 1; i >= 0; i--) - { - if (_pendingLaunches[i].Weapon == uid) - _pendingLaunches.RemoveAt(i); - } - } - private readonly record struct PendingLaunch( EntityUid Weapon, EntityUid User, EntityCoordinates FireCoordinates, - TimeSpan FireTime); + EntityUid TargetGrid, + TimeSpan FireTime, + bool NoServer, + bool Fired = false, + TimeSpan ExpireTime = default); } diff --git a/Content.Server/_Mono/FireControl/FireControlSystem.cs b/Content.Server/_Mono/FireControl/FireControlSystem.cs index f3c09c285e7..369e279040c 100644 --- a/Content.Server/_Mono/FireControl/FireControlSystem.cs +++ b/Content.Server/_Mono/FireControl/FireControlSystem.cs @@ -533,47 +533,41 @@ public bool AttemptFire(EntityUid weapon, EntityUid user, EntityCoordinates coor var weaponPos = weaponCoords.Position; var targetCoords = coords.ToMap(EntityManager, _xform); var targetPos = targetCoords.Position; - var fireCoords = coords; // Calculate direction var direction = targetPos - weaponPos; - // Forge-Change-Start: torpedo launchers are static tubes. The cursor picks a - // target grid, but the launch vector comes from the tube's own orientation. + // Forge-Change-Start: static torpedo tubes use the cursor only to pick a target grid. var isTorpedoLauncher = _forgeTorpedoLauncherQuery.TryComp(weapon, out var torpedoLauncher); if (isTorpedoLauncher) { direction = _forgeTorpedoLauncher.GetLaunchDirection(weaponXform); - if (!_forgeTorpedoLauncher.TryPrepareLaunch( + return _forgeTorpedoLauncher.TryQueueLaunch( weapon, + user, coords, direction, torpedoLauncher, weaponXform, - out fireCoords)) - { - return false; - } + noServer); } // Forge-Change-End - else - { - var distance = direction.Length(); - if (distance <= float.Epsilon) - return false; // Can't fire at the same position - direction = Vector2.Normalize(direction); + var distance = direction.Length(); + if (distance <= float.Epsilon) + return false; // Can't fire at the same position - // Check for obstacles in the firing direction - if (!CanFireInDirection(weapon, weaponPos, direction, targetPos, weaponXform.MapID)) - return false; - } + direction = Vector2.Normalize(direction); + + // Check for obstacles in the firing direction + if (!CanFireInDirection(weapon, weaponPos, direction, targetPos, weaponXform.MapID)) + return false; // Set the cooldown for next firing comp.NextFire = _timing.CurTime + TimeSpan.FromSeconds(comp.FireCooldown); - if (!isTorpedoLauncher && _fireRotateQuery.HasComp(weapon)) // Forge-Change: torpedo shafts stay static. + if (_fireRotateQuery.HasComp(weapon)) { var goalAngle = Angle.FromWorldVec(direction); _rotateToFace.TryRotateTo(weapon, goalAngle, 0f, Angle.FromDegrees(1), float.MaxValue, weaponXform); @@ -581,17 +575,9 @@ public bool AttemptFire(EntityUid weapon, EntityUid user, EntityCoordinates coor // Try to get a gun component and fire the weapon if (!_gunQuery.TryComp(weapon, out var gun)) - { - if (isTorpedoLauncher) - _forgeTorpedoLauncher.CancelPreparedLaunch(weapon); - return false; - } - if (isTorpedoLauncher) - _forgeTorpedoLauncher.QueueLaunch(weapon, user, fireCoords, torpedoLauncher!); - else - _gun.AttemptShots(user, weapon, gun, fireCoords, TimeSpan.FromSeconds(0.2)); + _gun.AttemptShots(user, weapon, gun, coords, TimeSpan.FromSeconds(0.2)); return true; } diff --git a/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs b/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs index 00b0480aa4e..cf0611fca68 100644 --- a/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs +++ b/Content.Server/_Mono/Projectiles/TargetSeeking/TargetSeekingSystem.cs @@ -3,7 +3,6 @@ using Content.Server.Shuttles.Components; using Content.Shared.Projectiles; using Robust.Server.GameObjects; -using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -298,7 +297,7 @@ public void AcquireTarget(EntityUid uid, TargetSeekingComponent component, Trans public Angle ApplyPredictiveTracking(Entity ent, Entity target, float frameTime) { // Get current positions - var currentTargetPosition = GetTargetWorldPosition(target); + var currentTargetPosition = GetTargetWorldPosition(target.Owner, target.Comp2); // Forge-Change var sourcePosition = _transform.GetWorldPosition(ent.Comp3); // Calculate current distance @@ -337,7 +336,7 @@ public Angle ApplyAdvancedTracking(Entity ent, Entity target, float frameTime) { // Get the angle directly toward the target - var angleToTarget = (GetTargetWorldPosition(target) - _transform.GetWorldPosition(ent.Comp)).ToWorldAngle(); + var angleToTarget = (GetTargetWorldPosition(target.Owner, target.Comp) - _transform.GetWorldPosition(ent.Comp)).ToWorldAngle(); // Forge-Change return angleToTarget; } - - private Vector2 GetTargetWorldPosition(Entity target) - { - if (TryComp(target.Owner, out var grid)) - return Vector2.Transform(grid.LocalAABB.Center, _transform.GetWorldMatrix(target.Comp)); - - return _transform.GetWorldPosition(target.Comp); - } - - private Vector2 GetTargetWorldPosition(Entity target) - { - if (TryComp(target.Owner, out var grid)) - return Vector2.Transform(grid.LocalAABB.Center, _transform.GetWorldMatrix(target.Comp2)); - - return _transform.GetWorldPosition(target.Comp2); - } } diff --git a/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml b/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml index 03a880fd8f6..999fd079ece 100644 --- a/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml +++ b/Resources/Prototypes/_Forge/Entities/Objects/Devices/Circuitboards/Machine/ship_weapons.yml @@ -400,7 +400,7 @@ id: WeaponTurretForgeHeavyTorpedoCircuitboard parent: ForgeShipWeaponCircuitboardT4 name: FHT-300 Gungnir heavy torpedo launcher machine board - description: A machine printed circuit board for an FHT-300 Gungnir heavy torpedo launcher. Ships love not needing line of sight, captains love not asking why. + description: A machine printed circuit board for an FHT-300 Gungnir heavy torpedo launcher. components: - type: MachineBoard prototype: WeaponTurretForgeHeavyTorpedoPortable diff --git a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml index c189b6abe32..02494c66924 100644 --- a/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml +++ b/Resources/Prototypes/_Forge/Entities/SpaceArtillery/heavy_torpedo.yml @@ -1,18 +1,16 @@ - type: entity - id: WeaponTurretForgeHeavyTorpedo - name: FHT-300 "Gungnir" тяжелая пусковая установка - suffix: For mapping - parent: - - BallisticArtilleryMapped - - BallisticArtilleryTier4HP - description: Тяжёлая пусковая установка для таких-же тяжёлых ракет. Может вести огонь без прямой видимости цели. + id: WeaponTurretForgeHeavyTorpedoBase + parent: BallisticArtilleryTier4HP + abstract: true + name: FHT-300 Gungnir heavy torpedo launcher + description: A heavy torpedo launcher for heavy guided torpedoes. It can fire without direct line of sight, but needs a clear muzzle lane. + components: - type: StaticPrice price: 18000 - type: Sprite sprite: _Forge/Objects/ShuttleWeapons/gungnir.rsi layers: - state: space_artillery - scale: 0.5, 0.5 - type: Appearance - type: ForgeTorpedoLauncher tileProbeDistance: 1.5 @@ -64,7 +62,7 @@ shape: Square respectZoom: true rotate: true - bounds: "-0.5,-1,0.5,1" + bounds: "-0.5,-1.5,0.5,1.5" - type: ShipGunType shipType: Missile - type: ShipGunClass @@ -73,81 +71,15 @@ repairTime: 45 repairCost: 160 +- type: entity + id: WeaponTurretForgeHeavyTorpedo + parent: [WeaponTurretForgeHeavyTorpedoBase, BallisticArtilleryMapped] + suffix: For mapping + - type: entity id: WeaponTurretForgeHeavyTorpedoPortable - name: FHT-300 "Гунгир" тяжёлая пусковая установка + parent: [WeaponTurretForgeHeavyTorpedoBase, BallisticArtillery] suffix: DO NOT MAP - parent: - - BallisticArtillery - - BallisticArtilleryTier4HP - description: Тяжёлая пусковая установка для таких-же тяжёлых ракет. Может вести огонь без прямой видимости цели. - components: - - type: StaticPrice - price: 18000 - - type: Sprite - sprite: _Forge/Objects/ShuttleWeapons/gungnir.rsi - layers: - - state: space_artillery - scale: 0.5, 0.5 - - type: Appearance - - type: ForgeTorpedoLauncher - tileProbeDistance: 1.5 - clearanceRayDistance: 1.75 - - type: AmmoCounter - - type: Battery - maxCharge: 90000 - startingCharge: 90000 - - type: ExaminableBattery - - type: WirelessNetworkConnection - range: 500 - - type: Gun - fireRate: 0.08 - recoil: 20 - minAngle: 0 - maxAngle: 0 - shootThermalSignature: 48000000 - soundGunshot: - path: /Audio/Weapons/Guns/Gunshots/rocket_launcher.ogg - soundEmpty: - path: /Audio/Weapons/Guns/EmptyAlarm/smg_empty_alarm.ogg - - type: SpaceArtillery - powerChargeRate: 600 - powerUsePassive: 1800 - powerUseActive: 0 - - type: Fixtures - fixtures: - fix1: - shape: !type:PhysShapeAabb - bounds: "-0.5,-1,0.5,1" - density: 800 - mask: - - MachineMask - layer: - - MachineLayer - - type: BatterySelfRecharger - autoRecharge: true - autoRechargeRate: 250 - - type: Actions - - type: ProjectileBatteryAmmoProvider - proto: ShipTorpedoForgeHeavy - fireCost: 30000 - - type: RadarBlip - radarColor: "#ff9d00" - scale: 2.5 - visibleFromOtherGrids: true - gridConfig: - color: "#ff9d00" - shape: Square - respectZoom: true - rotate: true - bounds: "-0.5,-1,0.5,1" - - type: ShipGunType - shipType: Missile - - type: ShipGunClass - shipClass: Superheavy - - type: ShipRepairable - repairTime: 45 - repairCost: 160 - type: entity id: ShipTorpedoForgeHeavy