From c32824dfa0348f56ec9e736e9411eafd9e79233c Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Wed, 11 Feb 2026 22:10:36 +0300
Subject: [PATCH 01/20] =?UTF-8?q?=D0=BA=D0=BE=D1=80=D0=B0=D0=B1=D0=BB?=
=?UTF-8?q?=D0=B8=D0=BA=D0=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
добавлено весло и паруса
---
.../Medieval/Ships/Oar/ServerOarSystem.cs | 36 ++++
.../Medieval/Ships/Sail/SailComponent.cs | 14 ++
.../Medieval/Ships/Sail/SailSystem.cs | 161 ++++++++++++++++++
.../Medieval/Ships/Wind/ServerWindSystem.cs | 13 ++
.../Medieval/Ships/Oar/OarComponent.cs | 19 +++
.../Imperial/Medieval/Ships/Oar/OarEvent.cs | 12 ++
.../Imperial/Medieval/Ships/Oar/OarSystem.cs | 134 +++++++++++++++
.../Medieval/Ships/Wind/SharedWindSystem.cs | 151 ++++++++++++++++
.../Skills/Systems/SharedSkillsSystem.cs | 7 +
.../Imperial/Medieval/Ships/oar.yml | 32 ++++
.../Imperial/Medieval/Ships/Oar.rsi/base.png | Bin 0 -> 1017 bytes
.../Imperial/Medieval/Ships/Oar.rsi/meta.json | 15 ++
12 files changed, 594 insertions(+)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Sail/SailComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Oar/OarEvent.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs
create mode 100644 Resources/Prototypes/Imperial/Medieval/Ships/oar.yml
create mode 100644 Resources/Textures/Imperial/Medieval/Ships/Oar.rsi/base.png
create mode 100644 Resources/Textures/Imperial/Medieval/Ships/Oar.rsi/meta.json
diff --git a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
new file mode 100644
index 00000000000..b10a30cf05b
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
@@ -0,0 +1,36 @@
+// using System.Numerics;
+// using Content.Server.Administration.Logs;
+// using Content.Shared.Database;
+// using Content.Shared.DoAfter;
+// using Content.Shared.Imperial.Medieval.Ships.Oar;
+// using Content.Shared.Imperial.Medieval.Skills;
+// using Content.Shared.Interaction;
+// using Content.Shared.Popups;
+// using Robust.Shared.Map;
+// using Robust.Shared.Physics.Components;
+// using Robust.Shared.Physics.Systems;
+// using Robust.Shared.Serialization;
+//
+// namespace Content.Server.Imperial.Medieval.Ships.Oar;
+//
+// ///
+// // /// This handles...
+// ///
+// public sealed class ServerOarSystem : EntitySystem
+// {
+// [Dependency] private readonly SharedPopupSystem _popup = default!;
+// [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+// [Dependency] private readonly SharedTransformSystem _transform = default!;
+// [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+// [Dependency] private readonly SharedSkillsSystem _skills = default!;
+// [Dependency] private readonly IAdminLogManager _adminLog = default!;
+//
+// public override void Initialize()
+// {
+//
+// }
+//
+//
+//
+//
+// }
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailComponent.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailComponent.cs
new file mode 100644
index 00000000000..631cf37f887
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailComponent.cs
@@ -0,0 +1,14 @@
+namespace Content.Server.Imperial.Medieval.Ships.Sail;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class SailComponent : Component
+{
+ [DataField("SailSize")]
+ public int SailSize = 1;
+
+ [DataField("Folded")]
+ public bool Folded;
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
new file mode 100644
index 00000000000..23c5be2cd95
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -0,0 +1,161 @@
+using System.Numerics;
+using Content.Shared._RD.Weight.Components;
+using Content.Shared._RD.Weight.Systems;
+using Content.Shared.DoAfter;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Imperial.Medieval.Ships.Wind;
+using Content.Shared.Imperial.Medieval.Skills;
+using Content.Shared.Popups;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Physics.Systems;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Imperial.Medieval.Ships.Sail;
+
+///
+/// This handles...
+///
+public sealed class SailSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedSkillsSystem _skills = default!;
+ [Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly RDWeightSystem _rdWeight = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ private const float DefaultReloadTimeSeconds = 1f;
+ private TimeSpan _nextCheckTime;
+
+ private int _windForce;
+ private int _windAngle;
+ ///
+ public override void Initialize()
+ {
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var curTime = _timing.CurTime;
+
+ if (curTime > _nextCheckTime)
+ {
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(DefaultReloadTimeSeconds);
+
+ // Плавные изменения ветра (0–10)
+ if (_windForce <= 0)
+ _windForce += _random.Next(0, 2);
+ else if (_windForce >= 10)
+ _windForce -= _random.Next(0, 2);
+ else
+ _windForce += _random.Next(-1, 2);
+
+ // Угол ветра: -45° до +45° (в градусах) — реалистично для моря
+ _windAngle += _random.Next(-5, 6); // ±5 градусов за шаг
+ _windAngle = Math.Clamp(_windAngle, -45, 45);
+
+ // --- Обработка каждого паруса ---
+ foreach (var sailComponent in EntityManager.EntityQuery())
+ {
+ if (sailComponent.Folded)
+ continue;
+
+ var sailEntity = sailComponent.Owner;
+ var boat = _transform.GetParentUid(sailEntity);
+ if (!EntityManager.TryGetComponent(boat, out PhysicsComponent? boatBody))
+ continue;
+
+ // Получаем углы в радианах
+ float sailAngleRad = (float)_transform.GetWorldRotation(sailEntity).Theta;
+ float boatAngleRad = (float)_transform.GetWorldRotation(boat).Theta;
+ float windAngleRad = _windAngle * MathF.PI / 180f; // ветер в радианах
+
+ // Направление ветра как вектор
+ Vector2 windDirection = new Vector2(
+ MathF.Cos(windAngleRad),
+ MathF.Sin(windAngleRad)
+ );
+
+ // Нормаль паруса — перпендикуляр к его поверхности (наружу)
+ // Парус — плоскость, нормаль — направление, в которое он "ловит" ветер
+ var sailNormalAngleRad = sailAngleRad + MathF.PI / 2f;
+ var sailNormal = new Vector2(
+ MathF.Cos(sailNormalAngleRad),
+ MathF.Sin(sailNormalAngleRad)
+ );
+
+ // Угол между ветром и нормалью паруса
+ var dot = Math.Clamp(Vector2.Dot(windDirection, sailNormal), -1f, 1f);
+ var angleBetween = MathF.Acos(dot);
+
+ // Эффективность: максимальна, когда ветер перпендикулярен парусу (0°)
+ // Минимальна, когда ветер параллелен (90°+)
+ var efficiency = MathF.Cos(angleBetween);
+
+ // Если ветер дует сзади (угол > 90°), всё равно даём слабую тягу
+ // (реальные паруса могут работать и на "бейсинге")
+ if (angleBetween > MathF.PI / 2f)
+ efficiency = MathF.Max(0.05f, efficiency); // 5% тяги сзади
+ else
+ efficiency = MathF.Max(0f, efficiency);
+
+ // Сила ветра = базовая сила × площадь × эффективность
+ var forceMagnitude = _windForce * sailComponent.SailSize * efficiency;
+
+ // Направление силы — вдоль нормали паруса
+ var forceDirection = sailNormal * forceMagnitude;
+
+ // Крутящий момент: сила × плечо × sin(разница между парусом и кораблём)
+ // Плечо — расстояние от центра корабля до центра паруса (условное)
+ var sailOffset = 0.5f; // метры — можно настроить в компоненте
+ var torqueFactor = MathF.Sin(sailAngleRad - boatAngleRad); // как сильно парус "выступает" вбок
+ var torque = forceMagnitude * sailOffset * torqueFactor * 0.1f; // масштабируем
+
+ var windEffect = new WindEffect
+ {
+ PushForce = forceDirection,
+ RotationTorque = torque
+ };
+
+ Push(sailEntity, sailComponent, windEffect);
+ }
+ }
+ }
+
+ private void Push(EntityUid sail, SailComponent sailComponent, WindEffect windForce)
+ {
+ var boat = _transform.GetParentUid(sail);
+
+ var entities = _lookup.GetEntitiesIntersecting(boat);
+
+ if (entities.Count > 1000)
+ return;
+
+ var weight = _rdWeight.GetTotal(boat);
+
+ foreach (var entity in entities)
+ {
+ if (HasComp(entity))
+ weight += _rdWeight.GetTotal(entity);
+ }
+
+ if (weight == 0)
+ weight = 10;
+ var impulse = windForce.PushForce;
+ var angleimpulse = windForce.RotationTorque;
+ if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
+ {
+ _physics.WakeBody(boat);
+ _physics.ApplyLinearImpulse(boat, impulse, body: body);
+ _physics.ApplyAngularImpulse(boat, angleimpulse);
+ }
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
new file mode 100644
index 00000000000..aad8226fda2
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
@@ -0,0 +1,13 @@
+namespace Content.Server.Imperial.Medieval.Ships.Wind;
+
+///
+/// This handles...
+///
+public sealed class ServerWindSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs b/Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs
new file mode 100644
index 00000000000..d54ee8f8d47
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs
@@ -0,0 +1,19 @@
+using System.Numerics;
+
+namespace Content.Shared.Imperial.Medieval.Ships.Oar;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class OarComponent : Component
+{
+ [DataField]
+ public int Power = 200;
+
+ [DataField]
+ public int SpeedModifier = 1;
+
+ [DataField]
+ public Vector2 Direction;
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Oar/OarEvent.cs b/Content.Shared/Imperial/Medieval/Ships/Oar/OarEvent.cs
new file mode 100644
index 00000000000..581fdef3718
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Oar/OarEvent.cs
@@ -0,0 +1,12 @@
+
+using Content.Shared.DoAfter;
+
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Imperial.Medieval.Ships.Oar;
+
+
+[Serializable, NetSerializable]
+public sealed partial class OnOarDoAfterEvent : SimpleDoAfterEvent
+{
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
new file mode 100644
index 00000000000..e0f0164ece7
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
@@ -0,0 +1,134 @@
+using System.Numerics;
+using Content.Shared._RD.Weight.Components;
+using Content.Shared._RD.Weight.Systems;
+using Content.Shared.Coordinates;
+using Content.Shared.DoAfter;
+using Content.Shared.Imperial.Medieval.Skills;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Popups;
+using Robust.Shared.Physics;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Physics.Systems;
+
+
+using Content.Shared.Database;
+using Content.Shared.Hands.EntitySystems;
+
+
+namespace Content.Shared.Imperial.Medieval.Ships.Oar;
+
+///
+/// This handles...
+///
+public sealed class OarSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedSkillsSystem _skills = default!;
+ [Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly RDWeightSystem _rdWeight = default!;
+public override void Initialize()
+ {
+ SubscribeLocalEvent(OnOarAfterInteract);
+ SubscribeLocalEvent(OnOarDoAfter);
+ }
+
+ private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInteractEvent args)
+ {
+ var playerEntity = args.User;
+
+ if (args.Handled || !args.CanReach )
+ return;
+
+ bool foundWater = false;
+ foreach (var entity in _lookup.GetEntitiesInRange(args.ClickLocation, 0.3f))
+ {
+ if (MetaData(entity).EntityPrototype?.ID == "MedievalWaterDeepDarkEntity")
+ {
+ foundWater = true;
+ break;
+ }
+ }
+ if (!foundWater)
+ return;
+
+ var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
+ var sdoAfter = new DoAfterArgs(EntityManager,
+ playerEntity,
+ time,
+ new OnOarDoAfterEvent(),
+ args.Target,
+ target: args.Used)
+ {
+ MovementThreshold = 0.5f,
+ BreakOnMove = true,
+ CancelDuplicate = true,
+ DistanceThreshold = 2,
+ BreakOnDamage = true,
+ RequireCanInteract = false,
+ BreakOnDropItem = true,
+ BreakOnHandChange = true,
+ };
+ if (!_doAfter.TryStartDoAfter(sdoAfter))
+ return;
+
+ var playerPosition = _transform.GetWorldPosition(playerEntity);
+ var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
+ var direction = (playerPosition - boatPosition).Normalized();
+ component.Direction = direction;
+ args.Handled = true;
+
+ }
+
+ private void OnOarDoAfter(EntityUid uid, MetaDataComponent component, OnOarDoAfterEvent args)
+ {
+ var item = _hands.GetActiveItem(args.User);
+ if (args.Cancelled || args.Handled || item == null)
+ return;
+
+ if (!TryComp(item, out var comp))
+ return;
+
+ Push(item.Value, comp.Direction, comp.Power, args.User);
+ args.Handled = true;
+ }
+
+ private void Push(EntityUid item, Vector2 direction, float power, EntityUid player)
+ {
+ power += power * (10 - _skills.GetSkillLevel(player, "Strength")) * 0.1f;
+
+ var boat = _transform.GetParentUid(player);
+
+ var entities = _lookup.GetEntitiesIntersecting(boat);
+
+ if (entities.Count > 1000)
+ return;
+
+ var weight = _rdWeight.GetTotal(boat);
+
+ foreach (var entity in entities)
+ {
+ if (HasComp(entity))
+ weight += _rdWeight.GetTotal(entity);
+ }
+
+ if (weight == 0)
+ weight = 10;
+ var impulse = direction * (power / weight);
+ var angleimpulse = (power / weight);
+ if (direction.X < 0)
+ angleimpulse = -angleimpulse;
+
+ if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
+ {
+ _physics.WakeBody(boat);
+ _physics.ApplyLinearImpulse(boat, impulse, body: body);
+ _physics.ApplyAngularImpulse(boat, angleimpulse);
+ }
+ }
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs
new file mode 100644
index 00000000000..6f8990921b8
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs
@@ -0,0 +1,151 @@
+using System.Numerics;
+using Robust.Shared.Maths;
+
+namespace Content.Shared.Imperial.Medieval.Ships.Wind;
+
+///
+/// This handles wind force calculations for sails.
+///
+public sealed class SharedWindSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+ // Initialization logic here if needed
+ }
+
+ ///
+ /// Calculates the aerodynamic forces acting on a sail due to wind.
+ ///
+ /// World position of the ship.
+ /// Current rotation of the ship in radians.
+ /// Angle of the sail relative to the ship's orientation (radians).
+ /// Effective area of the sail (m²).
+ /// Current time for dynamic wind simulation.
+ /// Density of air (default: 1.2 kg/m³).
+ /// A containing force, torque, and wind data.
+ public static WindEffect CalculateWindForce(
+ Vector2 shipPosition,
+ float shipRotation,
+ float sailAngle,
+ float sailArea,
+ float time = 0f,
+ float airDensity = 1.2f)
+ {
+ // Get wind vector at ship's position
+ var windVector = GetWindField(shipPosition, time);
+ var windStrength = windVector.Length();
+ var windDirection = windVector.Normalized();
+
+ // Absolute sail angle in world coordinates
+ var absoluteSailAngle = shipRotation + sailAngle;
+
+ // Angle between wind direction and sail normal
+ var windAngle = MathF.Atan2(windDirection.Y, windDirection.X);
+ var angleDiff = absoluteSailAngle - windAngle;
+ var angleOfAttack = NormalizeAngle(angleDiff);
+
+ // Lift and drag coefficients based on angle of attack
+ var liftCoefficient = MathF.Sin(2f * angleOfAttack);
+ var dragCoefficient = MathF.Abs(MathF.Cos(angleOfAttack));
+
+ // Dynamic pressure
+ var dynamicPressure = 0.5f * airDensity * windStrength * windStrength;
+
+ // Force magnitudes
+ var liftForce = liftCoefficient * dynamicPressure * sailArea;
+ var dragForce = dragCoefficient * dynamicPressure * sailArea;
+
+ // Sail orientation vectors
+ Vector2 sailDirection = new(MathF.Cos(absoluteSailAngle), MathF.Sin(absoluteSailAngle)); // Along sail
+ Vector2 sailNormal = new(-MathF.Sin(absoluteSailAngle), MathF.Cos(absoluteSailAngle)); // Perpendicular to sail
+
+ // Force components
+ var liftVector = sailNormal * liftForce;
+ var dragVector = sailDirection * dragForce;
+
+ // Total force
+ var totalForce = liftVector + dragVector;
+
+ // Torque calculation
+ var leverArm = 1f; // Distance from center of mass to sail (can be parameterized)
+ var torque = CalculateTorque(totalForce, absoluteSailAngle, leverArm);
+
+ return new WindEffect
+ {
+ PushForce = totalForce,
+ RotationTorque = angleDiff,
+ WindStrength = windStrength,
+ WindDirection = windDirection
+ };
+ }
+
+ ///
+ /// Normalizes an angle to the range [-π, π]
+ ///
+ private static float NormalizeAngle(float angle)
+ {
+ while (angle > MathF.PI)
+ angle -= MathF.Tau;
+ while (angle < -MathF.PI)
+ angle += MathF.Tau;
+ return angle;
+ }
+
+ ///
+ /// Simple procedural wind field simulation
+ ///
+ private static Vector2 GetWindField(Vector2 position, float time = 0f)
+ {
+ var x = position.X;
+ var y = position.Y;
+
+ var u = MathF.Sin(x / 2f + time) * MathF.Cos(y / 3f) + 0.5f * MathF.Sin(x / 5f + y / 7f);
+ var v = MathF.Cos(x / 3f + time) * MathF.Sin(y / 2f) + 0.5f * MathF.Cos(x / 7f - y / 5f);
+
+ return new Vector2(u, v);
+ }
+
+ ///
+ /// Calculates rotational torque applied by wind force
+ ///
+ private static float CalculateTorque(Vector2 force, float sailAngle, float leverArm)
+ {
+ if (force.LengthSquared() < 0.001f)
+ return 0f;
+
+ var forceDirection = force.Normalized();
+ Vector2 leverDirection = new(-MathF.Sin(sailAngle), MathF.Cos(sailAngle));
+
+ // Cross product in 2D: F × r
+ var crossProduct = forceDirection.X * leverDirection.Y - forceDirection.Y * leverDirection.X;
+
+ return force.Length() * leverArm * crossProduct;
+ }
+}
+
+///
+/// Represents the effect of wind on a sail.
+///
+public struct WindEffect
+{
+ ///
+ /// Net force applied to the ship in world coordinates.
+ ///
+ public Vector2 PushForce;
+
+ ///
+ /// Rotational torque around the ship's center.
+ ///
+ public float RotationTorque;
+
+ ///
+ /// Magnitude of the wind vector at this point.
+ ///
+ public float WindStrength;
+
+ ///
+ /// Direction of the wind (normalized).
+ ///
+ public Vector2 WindDirection;
+}
diff --git a/Content.Shared/Imperial/Medieval/Skills/Systems/SharedSkillsSystem.cs b/Content.Shared/Imperial/Medieval/Skills/Systems/SharedSkillsSystem.cs
index 02493f6648a..9250b2de118 100644
--- a/Content.Shared/Imperial/Medieval/Skills/Systems/SharedSkillsSystem.cs
+++ b/Content.Shared/Imperial/Medieval/Skills/Systems/SharedSkillsSystem.cs
@@ -81,4 +81,11 @@ public static int GetPointsCost(int level)
return sum;
}
+
+ public int GetSkillLevel(EntityUid uid, string skill)
+ {
+ if (!TryComp(uid, out var skillComponent))
+ return 1;
+ return skillComponent.Levels.GetValueOrDefault(skill, 1);
+ }
}
diff --git a/Resources/Prototypes/Imperial/Medieval/Ships/oar.yml b/Resources/Prototypes/Imperial/Medieval/Ships/oar.yml
new file mode 100644
index 00000000000..961cd197858
--- /dev/null
+++ b/Resources/Prototypes/Imperial/Medieval/Ships/oar.yml
@@ -0,0 +1,32 @@
+- type: entity
+ name: Весло
+ parent: BaseItem
+ id: MedievalOar
+ description: Обычное деревянное весло которое всем своим видом вселяет в тебя желание кого то ударить им.
+ components:
+ - type: QuestItem
+ contractName: "любое двуручное оружие"
+ - type: Sharp
+ - type: Sprite
+ sprite: Imperial/Medieval/Ships/Oar.rsi
+ state: base
+ - type: MeleeParry
+ parryChanse: 0.2
+ - type: MeleeWeapon
+ animation: CP14WeaponArcThrust
+ wideAnimation: CP14WeaponArcSlash
+ cPSwingBeverage: true
+ cPAnimationOffset: 2
+ clickDamageModifier: 1.32
+ wideAnimationRotation: -140
+ attackRate: 0.65
+ range: 2.75
+ angle: 0
+ damage:
+ types:
+ Piercing: 0
+ soundHit:
+ path: /Audio/Weapons/bladeslice.ogg
+ soundSwing:
+ path: /Audio/Imperial/Medieval/spear_swing.ogg
+ - type: Oar
\ No newline at end of file
diff --git a/Resources/Textures/Imperial/Medieval/Ships/Oar.rsi/base.png b/Resources/Textures/Imperial/Medieval/Ships/Oar.rsi/base.png
new file mode 100644
index 0000000000000000000000000000000000000000..c86bb651eea6f91cc352eaca16ae4b1b29c44d54
GIT binary patch
literal 1017
zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9F5M?jcysy3fA0|WDF
zPZ!6KiaBrR_-BbYiX3wni0wOJv7nkcvZA?x{e+%*!A##ggVj45rKj&~wB{H1z^2Ev
z%iMsia9Y=ePnI^9U%q>}fBoxf+d6v=;|VWct@^%t)w@^gR<#>Dx-y;cV36cgP-aX~
zY3N~@Fp`wpqU-NIv$0MOLb>zao&c6EFzxUDg^!1yz?ay5l
zac3inyV-#g>>m!zEqGer%}9VL=h7k%4n>9@*&1biMWzzQ9R^8WHK&&PTU`H@Blu{Mk7&Zd^b%GJ^<9eF
zSY|bR>y|v$uGx5tDPrsW4Ph73d~Zhtuo&!~r}So>#?A(hgXS}YCUH3^?q0Ldm-o}O
zs+tKt4OeS)n0j{b@j4!#9K2?--%X)O<&LipbTdrcuBR!GBOw10p9mFvwHS$#Br
zxOs6d=6tca(A8u@x%Tl0r8}$-Ccgi8dU18*{GhkyYeb)zs~_CW^*%jp9g{%Kp5sTQ
zb?^8-=sW&x+6*NL#puWnotqwdu3FAw&iJ!;-h@Qyd+{-GzU#h8pQzray|vaPAWWZg
zoi2mvktX}6`|SIt9zNA#^zE+OaxQVkYhOjot6yy@3=9cqtJ(SC?q+Q%odps#t2G1N
z_r%^jyTamJ&T^faDlZ8gh5g6xEM&dEViH4Hs{FQ-R}vV_YRmDipV443lt`B!VpF8(eFQbcjonBAi#uuBF{*|L-oIi})m`!$Vi~JG-%*za(
Lu6{1-oD!M
Date: Thu, 12 Feb 2026 08:18:41 +0300
Subject: [PATCH 02/20] =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B0=D0=B5=D0=BC=20?=
=?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BD=D1=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
волны в процессе
---
.../Medieval/Ships/Wave/WaveComponent.cs | 30 +++++
.../Medieval/Ships/Wave/WaveSystem.cs | 108 ++++++++++++++++++
.../Imperial/Medieval/Ships/Oar/OarSystem.cs | 2 +-
3 files changed, 139 insertions(+), 1 deletion(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
new file mode 100644
index 00000000000..7005d0d096a
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
@@ -0,0 +1,30 @@
+using Content.Shared.Damage;
+
+namespace Content.Server.Imperial.Medieval.Ships.Wave;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class WaveComponent : Component
+{
+ ///
+ /// Damage specifier that is multiplied against the calculated damage amount to determine what damage is applied to the colliding entity.
+ ///
+ ///
+ /// The values of this should add up to 1 or else the damage will be scaled.
+ ///
+ [DataField]
+ public DamageSpecifier DamageTypes = new();
+
+ ///
+ /// A list of entities that this meteor has collided with. used to ensure no double collisions occur.
+ ///
+ [DataField]
+ public HashSet HitList = new();
+
+ [DataField]
+ public float Strength = 1;
+ [DataField]
+ public float Direction = 1;;
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
new file mode 100644
index 00000000000..d800f6ac8dc
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -0,0 +1,108 @@
+using Content.Server.Destructible;
+using Content.Shared.Construction.Conditions;
+using Content.Shared.Damage;
+using Content.Shared.Mobs.Systems;
+using Content.Shared.Physics;
+using Robust.Server.GameObjects;
+using Robust.Shared.Physics;
+using Robust.Shared.Physics.Events;
+using Robust.Shared.Player;
+using Robust.Shared.Map;
+using Robust.Shared.Timing;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Random;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Imperial.Medieval.Ships.Wave;
+
+public sealed class WaveSystem : EntitySystem
+{
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly DamageableSystem _damageable = default!;
+ [Dependency] private readonly DestructibleSystem _destructible = default!;
+ [Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
+ [Dependency] private readonly PhysicsSystem _physics = default!; // <-- КЛЮЧЕВОЙ ИЗМЕНЕНИЕ
+
+ private readonly Random _random = new();
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnCollide);
+ }
+
+ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideEvent args)
+ {
+ if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.OtherEntity))
+ return;
+
+ // Пропускаем, если уже толкали эту сущность
+ if (component.HitList.Contains(args.OtherEntity))
+ return;
+
+ // --- 1. Толкаем сущность через PhysicsSystem ---
+ if (_entityManager.TryGetComponent(args.OtherEntity, out var physics))
+ {
+ // Усиление толчка: 1.5x от силы волны
+ var force = component.Strength * 1.5f;
+ var impulse = component.Direction * force;
+
+ // Правильный способ: через PhysicsSystem
+ _physics.ApplyImpulse(args.OtherEntity, impulse);
+
+ // Визуальный эффект: "мокрый"
+ if (_entityManager.TryGetComponent(args.OtherEntity, out var appearance))
+ appearance.SetState("wet", true);
+ }
+
+ // --- 2. Проверка: тайл на корабле? ---
+ var otherPos = _entityManager.GetComponent(args.OtherEntity).Coordinates;
+ var tileRef = _mapManager.GetTileRef(otherPos);
+
+ // Проверяем, что это корабельная сетка
+ if (!IsTileOnShip(tileRef.GridId))
+ return;
+
+ // Проверяем, что тайл — не дыра
+ if (_entityManager.TryGetComponent(tileRef.GridId, out var tileGrid))
+ {
+ var tile = tileGrid.GetTile(tileRef.TilePosition);
+
+ if (IsTileHole(tile))
+ return;
+
+ // Шанс дыры: 20% при силе 2, 60% при силе 10
+ float chance = Math.Clamp((float)component.Strength / 10f * 0.6f, 0.2f, 0.6f);
+ if (_random.NextFloat() < chance)
+ {
+ MakeTileHole(tileRef.GridId, tileRef.TilePosition);
+ }
+ }
+
+ // --- 3. Запоминаем удар ---
+ component.HitList.Add(args.OtherEntity);
+ }
+
+ private bool IsTileOnShip(MapGridId gridId)
+ {
+ // Упрощённая проверка — замените на вашу логику (например, по компоненту ShipComponent)
+ return gridId.ToString().StartsWith("ShipGrid_");
+ }
+
+ private bool IsTileHole(Tile tile)
+ {
+ // Замените на ваш тип дыры, если используете кастомный TileType
+ return tile.Type == TileType.Hole;
+ }
+
+ private void MakeTileHole(MapGridId gridId, Vector2i tilePos)
+ {
+ if (!_entityManager.TryGetComponent(gridId, out var tileComponent))
+ return;
+
+ tileComponent.SetTile(tilePos, new Tile(TileType.Hole));
+
+ // Опционально: звук
+ // _audio.PlayPvs("wave_hole.wav", gridId, tilePos);
+ }
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
index e0f0164ece7..0df7cb2eb35 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
@@ -32,7 +32,7 @@ public sealed class OarSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly RDWeightSystem _rdWeight = default!;
-public override void Initialize()
+ public override void Initialize()
{
SubscribeLocalEvent(OnOarAfterInteract);
SubscribeLocalEvent(OnOarDoAfter);
From f4b1bd6d38a2deb5430ed7f8758806890d44daf1 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Thu, 12 Feb 2026 22:12:03 +0300
Subject: [PATCH 03/20] =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BD=D1=8B=20=D1=83?=
=?UTF-8?q?=D1=80=D0=B0=D0=B0=D0=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ура волнам
---
.../Ships/Wave/Spawn/SpawnWaveComponent.cs | 10 ++
.../Ships/Wave/Spawn/SpawnWaveSystem.cs | 36 +++++
.../Medieval/Ships/Wave/WaveComponent.cs | 2 +-
.../Medieval/Ships/Wave/WaveSystem.cs | 142 +++++++++++-------
.../Imperial/Medieval/Ships/wave.yml | 57 +++++++
5 files changed, 192 insertions(+), 55 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs
create mode 100644 Resources/Prototypes/Imperial/Medieval/Ships/wave.yml
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs
new file mode 100644
index 00000000000..54e3d9b996f
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Server.Imperial.Medieval.Ships.Wave;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class SpawnWaveComponent : Component
+{
+
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs
new file mode 100644
index 00000000000..83ecc4f9371
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs
@@ -0,0 +1,36 @@
+using Content.Shared.Damage;
+using Robust.Server.GameObjects;
+using Robust.Shared.Map;
+
+namespace Content.Server.Imperial.Medieval.Ships.Wave;
+
+///
+/// Спавнит волны, щиииииткод
+///
+public sealed class SpawnWaveSystem : EntitySystem
+{
+ [Dependency] private readonly SharedMapSystem _map = default!;
+ [Dependency] private readonly TransformSystem _transform = default!;
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly EntityManager _entityManager = default!;
+ [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnInit);
+ }
+
+ private void OnInit(EntityUid uid, SpawnWaveComponent component, ComponentInit args)
+ {
+ var entcoords = _transform.GetMoverCoordinates(uid);
+ var mapcoords = _transform.GetMapCoordinates(uid);
+ var grid = _mapManager.CreateGridEntity(mapcoords.MapId);
+ _transform.SetCoordinates(grid, entcoords);
+ EnsureComp(grid);
+ _tileDefinitionManager.TryGetDefinition("FloorWood", out var tileDefinition);// сюда поставить воду
+ if (tileDefinition == null)
+ return;
+ _map.SetTile(grid, new Vector2i(0,0),new Tile(tileDefinition.TileId, 0, 0));// создаёт тайлик воды надо поставить воду вон туда
+ _entityManager.DeleteEntity(uid);
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
index 7005d0d096a..1253e17b221 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
@@ -26,5 +26,5 @@ public sealed partial class WaveComponent : Component
[DataField]
public float Strength = 1;
[DataField]
- public float Direction = 1;;
+ public float Direction = 1;
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index d800f6ac8dc..20e05f39941 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -1,13 +1,22 @@
+using System.Linq;
+using System.Numerics;
using Content.Server.Destructible;
using Content.Shared.Construction.Conditions;
using Content.Shared.Damage;
+using Content.Shared.Maps;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
+using Content.Shared.Popups;
+using Content.Shared.Tiles;
+using Content.Shared.Trigger.Components;
using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
@@ -18,91 +27,116 @@ namespace Content.Server.Imperial.Medieval.Ships.Wave;
public sealed class WaveSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly DestructibleSystem _destructible = default!;
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
- [Dependency] private readonly PhysicsSystem _physics = default!; // <-- КЛЮЧЕВОЙ ИЗМЕНЕНИЕ
+ [Dependency] private readonly PhysicsSystem _physics = default!;
+ [Dependency] private readonly FloorTileSystem _floorTileSystem = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly TransformSystem _transform = default!;
+ [Dependency] private readonly TileSystem _tile = default!;
+ [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+
private readonly Random _random = new();
+ public (string, ushort)[] Stages =
+ {
+ ("FloorWood", (ushort)1),
+ ("FloorSteel", (ushort)2),
+ ("Plating", (ushort)3),
+ ("FloorWhite", (ushort)4)
+ };
public override void Initialize()
{
SubscribeLocalEvent(OnCollide);
+
+ foreach (var stage in Stages)
+ {
+ _tileDefinitionManager.TryGetDefinition(stage.Item1, out var tileDefinition);
+ if (tileDefinition == null)
+ continue;
+ var full = Stages.Index();
+
+ int index = 0;
+ foreach (var hah in full)
+ {
+ if (hah.Item2 == stage)
+ {
+ index = hah.Item1;
+ break;
+ }
+ }
+ Stages[index] = (stage.Item1, tileDefinition.TileId);
+ }
}
+
private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideEvent args)
{
if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.OtherEntity))
return;
-
- // Пропускаем, если уже толкали эту сущность
if (component.HitList.Contains(args.OtherEntity))
return;
- // --- 1. Толкаем сущность через PhysicsSystem ---
- if (_entityManager.TryGetComponent(args.OtherEntity, out var physics))
- {
- // Усиление толчка: 1.5x от силы волны
- var force = component.Strength * 1.5f;
- var impulse = component.Direction * force;
-
- // Правильный способ: через PhysicsSystem
- _physics.ApplyImpulse(args.OtherEntity, impulse);
+ var collisionPos = _transform.GetMapCoordinates(args.OurEntity);
+ var gridEntity = args.OtherEntity;
+ _popup.PopupEntity(Loc.GetString($"{gridEntity}"), uid);
+ if (!_entityManager.TryGetComponent(gridEntity, out var mapGridComp))
+ return;
+ _popup.PopupEntity(Loc.GetString($"{gridEntity}"), uid);
- // Визуальный эффект: "мокрый"
- if (_entityManager.TryGetComponent(args.OtherEntity, out var appearance))
- appearance.SetState("wet", true);
- }
+ var grid = new Entity(gridEntity, mapGridComp);
+ var tileRef = _map.GetTileRef(grid, collisionPos);
- // --- 2. Проверка: тайл на корабле? ---
- var otherPos = _entityManager.GetComponent(args.OtherEntity).Coordinates;
- var tileRef = _mapManager.GetTileRef(otherPos);
+ var centerTilePos = tileRef.GridIndices;
+ const float radiusTiles = 1.5f;
- // Проверяем, что это корабельная сетка
- if (!IsTileOnShip(tileRef.GridId))
- return;
- // Проверяем, что тайл — не дыра
- if (_entityManager.TryGetComponent(tileRef.GridId, out var tileGrid))
+ var nearbyTiles = new List();
+ for (int dx = -2; dx <= 2; dx++)
{
- var tile = tileGrid.GetTile(tileRef.TilePosition);
-
- if (IsTileHole(tile))
- return;
-
- // Шанс дыры: 20% при силе 2, 60% при силе 10
- float chance = Math.Clamp((float)component.Strength / 10f * 0.6f, 0.2f, 0.6f);
- if (_random.NextFloat() < chance)
+ for (int dy = -2; dy <= 2; dy++)
{
- MakeTileHole(tileRef.GridId, tileRef.TilePosition);
+ var tilePos = centerTilePos + new Vector2i(dx, dy);
+ var tile = _map.GetTileRef(grid, tilePos);
+ if (tile.Tile.IsEmpty)
+ continue;
+
+ var distance = Vector2.Distance(centerTilePos, tilePos);
+ if (distance <= radiusTiles)
+ nearbyTiles.Add(tilePos);
}
}
- // --- 3. Запоминаем удар ---
- component.HitList.Add(args.OtherEntity);
- }
+ _random.Shuffle(nearbyTiles);
+ int tilesToReplace = Math.Min(2, nearbyTiles.Count);
- private bool IsTileOnShip(MapGridId gridId)
- {
- // Упрощённая проверка — замените на вашу логику (например, по компоненту ShipComponent)
- return gridId.ToString().StartsWith("ShipGrid_");
- }
-
- private bool IsTileHole(Tile tile)
- {
- // Замените на ваш тип дыры, если используете кастомный TileType
- return tile.Type == TileType.Hole;
- }
- private void MakeTileHole(MapGridId gridId, Vector2i tilePos)
- {
- if (!_entityManager.TryGetComponent(gridId, out var tileComponent))
- return;
- tileComponent.SetTile(tilePos, new Tile(TileType.Hole));
+ for (int i = 0; i < tilesToReplace; i++)
+ {
+ var tilePos = nearbyTiles[i];
+ _map.TryGetTile(grid, tilePos, out var tile);
- // Опционально: звук
- // _audio.PlayPvs("wave_hole.wav", gridId, tilePos);
+ if (tile.TypeId == Stages[Stages.Length].Item2)
+ continue;
+ var index = 0;
+ foreach (var stage in Stages)
+ {
+ if (stage.Item2 == tile.TypeId)
+ break;
+ index++;
+ }
+ _map.SetTile(grid.Owner, grid , tilePos, new Tile(Stages[index+1].Item2, 0, 0));
+ }
+ if (!TerminatingOrDeleted(args.OtherEntity))
+ component.HitList.Add(args.OtherEntity);
+ _entityManager.DeleteEntity(uid);
}
}
diff --git a/Resources/Prototypes/Imperial/Medieval/Ships/wave.yml b/Resources/Prototypes/Imperial/Medieval/Ships/wave.yml
new file mode 100644
index 00000000000..fe3d5178da2
--- /dev/null
+++ b/Resources/Prototypes/Imperial/Medieval/Ships/wave.yml
@@ -0,0 +1,57 @@
+- type: entity
+ id: BaseWave
+ name: meteor
+ description: You prefer them when they're burning up in the atmosphere.
+ abstract: true
+ components:
+ - type: Sprite
+ noRot: false
+ sprite: Objects/Misc/meteor.rsi
+ - type: Projectile
+ damage: {}
+ deleteOnCollide: false
+ - type: SpawnWave
+ - type: TimedDespawn
+ lifetime: 120
+ - type: Clickable
+ - type: Physics
+ bodyType: Dynamic
+ bodyStatus: InAir
+ angularDamping: 0
+ linearDamping: 0
+ - type: Fixtures
+ fixtures:
+ projectile:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.4
+ density: 100
+ hard: false
+ layer:
+ - MapGrid
+ mask:
+ - MapGrid
+ - Impassable
+ - type: Damageable
+ damageContainer: Inorganic
+ - type: TileFrictionModifier
+ modifier: 0
+
+- type: entity
+ parent: BaseWave
+ id: WaveLarge
+ suffix: Large
+ components:
+ - type: Sprite
+ state: big
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 1200
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - !type:PlaySoundBehavior
+ sound:
+ collection: MetalBreak
\ No newline at end of file
From cc4e761b11cb9ec3f66e0190a82de1b9a9ec8476 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Sat, 14 Feb 2026 14:15:15 +0300
Subject: [PATCH 04/20] =?UTF-8?q?=D0=9C=D0=B0=D0=BF=D1=8B=20=D1=82=D0=BE?=
=?UTF-8?q?=D0=BF=D1=8F=D1=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
финал фикс волн и мапы топят
---
.../Ships/PlayerDrowning/DrownerComponent.cs | 9 ++
.../PlayerDrowning/PlayerDrowningComponent.cs | 11 +++
.../PlayerDrowning/PlayerDrowningSystem.cs | 79 +++++++++++++++++
.../Ships/Wave/Spawn/SpawnWaveComponent.cs | 5 +-
.../Ships/Wave/Spawn/SpawnWaveSystem.cs | 8 +-
.../Medieval/Ships/Wave/WaveComponent.cs | 3 +
.../Medieval/Ships/Wave/WaveSystem.cs | 85 +++++++++++--------
7 files changed, 161 insertions(+), 39 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/PlayerDrowning/DrownerComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/DrownerComponent.cs b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/DrownerComponent.cs
new file mode 100644
index 00000000000..5372d9621df
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/DrownerComponent.cs
@@ -0,0 +1,9 @@
+namespace Content.Server.Imperial.Medieval.Ships.PlayerDrowning;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class DrownerComponent : Component
+{
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs
new file mode 100644
index 00000000000..1f01a73223a
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs
@@ -0,0 +1,11 @@
+namespace Content.Server.Imperial.Medieval.Ships.PlayerDrowning;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class PlayerDrowningComponent : Component
+{
+ [DataField("drownTime")]
+ public int DrownTime = 15;
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
new file mode 100644
index 00000000000..da4a2878c5d
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
@@ -0,0 +1,79 @@
+using Content.Shared.Damage.Components;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Imperial.Medieval.Ships.PlayerDrowning;
+
+///
+/// This handles...
+///
+public sealed class PlayerDrowningSystem : EntitySystem
+{
+ private const float DefaultReloadTimeSeconds = 1f;
+ private const int DrownTimeMax = 15;
+ private TimeSpan _nextCheckTime;
+
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly EntityManager _entityManager = default!;
+
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+ _nextCheckTime = _timing.CurTime + TimeSpan.FromSeconds(DefaultReloadTimeSeconds);
+
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var curTime = _timing.CurTime;
+
+ if (curTime > _nextCheckTime)
+ {
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(DefaultReloadTimeSeconds);
+
+ foreach (var component in EntityManager.EntityQuery())
+ {
+ if (!TryComp(component.Owner, out var map))
+ return;
+
+ var drowningPlayers = new HashSet>();
+
+ _lookup.GetEntitiesOnMap(map.MapId, drowningPlayers);
+
+ foreach (var entity in drowningPlayers)
+ {
+ var transformComp = entity.Comp;
+ var uid = entity.Owner;
+ ProcessDrowning(uid, transformComp);
+ }
+ }
+ }
+ }
+
+ private void ProcessDrowning(EntityUid uid, TransformComponent transform)
+ {
+ if (!TryComp(uid, out var drowner))
+ EnsureComp(uid);
+ else
+ {
+ if (TryComp(uid, out var stamina))
+ {
+ if (stamina.Critical)
+ _entityManager.DeleteEntity(uid);
+ else
+ {
+ stamina.StaminaDamage += 1;
+ }
+ }
+ else if (drowner.DrownTime >= DrownTimeMax)
+ {
+ _entityManager.DeleteEntity(uid);
+ }
+ drowner.DrownTime += 1;
+ }
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs
index 54e3d9b996f..14f7c13109e 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveComponent.cs
@@ -1,4 +1,4 @@
-namespace Content.Server.Imperial.Medieval.Ships.Wave;
+namespace Content.Server.Imperial.Medieval.Ships.Wave.Spawn;
///
/// This is used for...
@@ -6,5 +6,6 @@ namespace Content.Server.Imperial.Medieval.Ships.Wave;
[RegisterComponent]
public sealed partial class SpawnWaveComponent : Component
{
-
+ [DataField]
+ public bool DeleteOnCollide = true;
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs
index 83ecc4f9371..bb6fa428403 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWaveSystem.cs
@@ -2,7 +2,7 @@
using Robust.Server.GameObjects;
using Robust.Shared.Map;
-namespace Content.Server.Imperial.Medieval.Ships.Wave;
+namespace Content.Server.Imperial.Medieval.Ships.Wave.Spawn;
///
/// Спавнит волны, щиииииткод
@@ -25,12 +25,14 @@ private void OnInit(EntityUid uid, SpawnWaveComponent component, ComponentInit a
var entcoords = _transform.GetMoverCoordinates(uid);
var mapcoords = _transform.GetMapCoordinates(uid);
var grid = _mapManager.CreateGridEntity(mapcoords.MapId);
- _transform.SetCoordinates(grid, entcoords);
- EnsureComp(grid);
+ var waveComponent = EnsureComp(grid);
+ waveComponent.DeleteOnCollide = component.DeleteOnCollide;
_tileDefinitionManager.TryGetDefinition("FloorWood", out var tileDefinition);// сюда поставить воду
if (tileDefinition == null)
return;
_map.SetTile(grid, new Vector2i(0,0),new Tile(tileDefinition.TileId, 0, 0));// создаёт тайлик воды надо поставить воду вон туда
+ if (HasComp(grid))
+ _transform.SetCoordinates(grid, entcoords);
_entityManager.DeleteEntity(uid);
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
index 1253e17b221..fbf46d35f98 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveComponent.cs
@@ -27,4 +27,7 @@ public sealed partial class WaveComponent : Component
public float Strength = 1;
[DataField]
public float Direction = 1;
+
+ [DataField]
+ public bool DeleteOnCollide = true;
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index 20e05f39941..ef766a09a02 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -1,8 +1,10 @@
using System.Linq;
using System.Numerics;
+using Content.Server.Administration.Logs;
using Content.Server.Destructible;
using Content.Shared.Construction.Conditions;
using Content.Shared.Damage;
+using Content.Shared.Database;
using Content.Shared.Maps;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
@@ -41,6 +43,7 @@ public sealed class WaveSystem : EntitySystem
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly IAdminLogManager _adminlogs = default!;
private readonly Random _random = new();
@@ -51,92 +54,106 @@ public sealed class WaveSystem : EntitySystem
("Plating", (ushort)3),
("FloorWhite", (ushort)4)
};
+ private const float RadiusTiles = 2f;
+ private bool _initialized;
public override void Initialize()
{
SubscribeLocalEvent(OnCollide);
- foreach (var stage in Stages)
+ }
+ private void Startup()
+ {
+ if (_initialized)
+ return;
+ if (Stages == null || Stages.Length == 0)
+ {
+ Logger.Error("Stages is null or empty! Cannot initialize.");
+ return;
+ }
+
+ // Используем for вместо foreach для изменения коллекции
+ for (int i = 0; i < Stages.Length; i++)
{
- _tileDefinitionManager.TryGetDefinition(stage.Item1, out var tileDefinition);
- if (tileDefinition == null)
+ var stage = Stages[i];
+ if (!_tileDefinitionManager.TryGetDefinition(stage.Item1, out var tileDefinition))
continue;
- var full = Stages.Index();
- int index = 0;
- foreach (var hah in full)
- {
- if (hah.Item2 == stage)
- {
- index = hah.Item1;
- break;
- }
- }
- Stages[index] = (stage.Item1, tileDefinition.TileId);
+ Stages[i] = (stage.Item1, tileDefinition.TileId);
+ _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"Тайл айди {tileDefinition.TileId} для '{stage.Item1}'");
}
+ _initialized = true;
}
-
private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideEvent args)
{
+ if (!_initialized)
+ Startup();
if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.OtherEntity))
return;
if (component.HitList.Contains(args.OtherEntity))
return;
-
+ EnsureComp(args.OurEntity);
var collisionPos = _transform.GetMapCoordinates(args.OurEntity);
var gridEntity = args.OtherEntity;
- _popup.PopupEntity(Loc.GetString($"{gridEntity}"), uid);
if (!_entityManager.TryGetComponent(gridEntity, out var mapGridComp))
return;
- _popup.PopupEntity(Loc.GetString($"{gridEntity}"), uid);
+
var grid = new Entity(gridEntity, mapGridComp);
var tileRef = _map.GetTileRef(grid, collisionPos);
+ var centerTilePos = _map.MapToGrid(grid, collisionPos);
- var centerTilePos = tileRef.GridIndices;
- const float radiusTiles = 1.5f;
-
-
+ var antiradius = (int)RadiusTiles*-1;
var nearbyTiles = new List();
- for (int dx = -2; dx <= 2; dx++)
+ for (int dx = antiradius; dx <= RadiusTiles; dx++)
{
- for (int dy = -2; dy <= 2; dy++)
+ for (int dy = antiradius; dy <= RadiusTiles; dy++)
{
- var tilePos = centerTilePos + new Vector2i(dx, dy);
+ var tilePos = centerTilePos + new EntityCoordinates(gridEntity, new Vector2(dx, dy)) ;
var tile = _map.GetTileRef(grid, tilePos);
+
if (tile.Tile.IsEmpty)
continue;
- var distance = Vector2.Distance(centerTilePos, tilePos);
- if (distance <= radiusTiles)
- nearbyTiles.Add(tilePos);
+ var distance = Vector2.Distance(centerTilePos.Position, tilePos.Position);
+ if (distance <= RadiusTiles)
+ nearbyTiles.Add(((int)tilePos.X, (int)tilePos.Y));
}
}
_random.Shuffle(nearbyTiles);
- int tilesToReplace = Math.Min(2, nearbyTiles.Count);
-
-
+ int tilesToReplace = Math.Min(_random.Next(0,4), nearbyTiles.Count);
+ _popup.PopupEntity(Loc.GetString($" {tilesToReplace}"), uid);
for (int i = 0; i < tilesToReplace; i++)
{
var tilePos = nearbyTiles[i];
- _map.TryGetTile(grid, tilePos, out var tile);
+ _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"тайл поз {tilePos} грид {grid} {_map.TryGetTile(grid, tilePos, out var tiles)}");
+ if (!_map.TryGetTile(grid, tilePos, out var tile))
+ continue;
+ var stagelast = Stages.Length-1;
+ _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"тайл айди {tile.TypeId} длина стейжеса {Stages.Length}");
- if (tile.TypeId == Stages[Stages.Length].Item2)
+ if (tile.TypeId == Stages[stagelast].Item2)
continue;
+ _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"грид2 {i}");
var index = 0;
foreach (var stage in Stages)
{
+ _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"грид3 {stage}");
if (stage.Item2 == tile.TypeId)
break;
index++;
}
+ if (index == stagelast+1)
+ index = 0;
_map.SetTile(grid.Owner, grid , tilePos, new Tile(Stages[index+1].Item2, 0, 0));
+ _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"индекс {index}");
}
if (!TerminatingOrDeleted(args.OtherEntity))
component.HitList.Add(args.OtherEntity);
- _entityManager.DeleteEntity(uid);
+ if (component.DeleteOnCollide)
+ _entityManager.DeleteEntity(args.OurEntity);
}
}
From ccd239ca4b6bfaba2d412a4510031ff001867975 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Sat, 14 Feb 2026 19:42:03 +0300
Subject: [PATCH 05/20] =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BD=D1=8B=20=D0=B8?=
=?UTF-8?q?=20=D1=83=D1=82=D0=BE=D0=BF=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?=
=?UTF-8?q?=D1=84=D1=83=D0=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../PlayerDrowning/PlayerDrowningComponent.cs | 5 ++-
.../PlayerDrowning/PlayerDrowningSystem.cs | 41 ++++++++++++-------
.../PlayerDrowning/UndrowableComponent.cs | 10 +++++
.../Medieval/Ships/Wave/WaveSystem.cs | 10 +----
4 files changed, 41 insertions(+), 25 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/PlayerDrowning/UndrowableComponent.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs
index 1f01a73223a..282e8fea95e 100644
--- a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs
+++ b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningComponent.cs
@@ -7,5 +7,8 @@ namespace Content.Server.Imperial.Medieval.Ships.PlayerDrowning;
public sealed partial class PlayerDrowningComponent : Component
{
[DataField("drownTime")]
- public int DrownTime = 15;
+ public int DrownTime;
+
+ [DataField("Undrowable")]
+ public bool Undrowable;
}
diff --git a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
index da4a2878c5d..1f0c1caa786 100644
--- a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
@@ -1,4 +1,6 @@
using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Systems;
+using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
@@ -16,6 +18,8 @@ public sealed class PlayerDrowningSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly EntityManager _entityManager = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedStaminaSystem _staminaSystem = default!;
///
public override void Initialize()
@@ -37,39 +41,46 @@ public override void Update(float frameTime)
foreach (var component in EntityManager.EntityQuery())
{
- if (!TryComp(component.Owner, out var map))
+ if (!TryComp(component.Owner, out var transform))
return;
-
- var drowningPlayers = new HashSet>();
-
- _lookup.GetEntitiesOnMap(map.MapId, drowningPlayers);
-
- foreach (var entity in drowningPlayers)
+ var childs = new List();
+ var childEnum = transform.ChildEnumerator;
+ while (childEnum.MoveNext(out var child))
{
- var transformComp = entity.Comp;
- var uid = entity.Owner;
- ProcessDrowning(uid, transformComp);
+ ProcessDrowning(child);
}
+
}
}
}
- private void ProcessDrowning(EntityUid uid, TransformComponent transform)
+ private void ProcessDrowning(EntityUid uid)
{
+ if (HasComp(uid))
+ return;
+
if (!TryComp(uid, out var drowner))
EnsureComp(uid);
else
{
+ if (drowner.Undrowable)
+ return;
+ if (HasComp(uid))
+ return;
+
if (TryComp(uid, out var stamina))
{
if (stamina.Critical)
- _entityManager.DeleteEntity(uid);
- else
{
- stamina.StaminaDamage += 1;
+ _entityManager.DeleteEntity(uid);
+ return;
}
+
+ if (_staminaSystem.TryTakeStamina(uid, 25, ignoreResist: true))
+ return;
+
}
- else if (drowner.DrownTime >= DrownTimeMax)
+ if (drowner.DrownTime >= DrownTimeMax)
{
_entityManager.DeleteEntity(uid);
}
diff --git a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/UndrowableComponent.cs b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/UndrowableComponent.cs
new file mode 100644
index 00000000000..8deb8fd34d2
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/UndrowableComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Server.Imperial.Medieval.Ships.PlayerDrowning;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class UndrowableComponent : Component
+{
+
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index ef766a09a02..fb279ed4aa2 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -67,10 +67,8 @@ private void Startup()
if (_initialized)
return;
if (Stages == null || Stages.Length == 0)
- {
- Logger.Error("Stages is null or empty! Cannot initialize.");
return;
- }
+
// Используем for вместо foreach для изменения коллекции
for (int i = 0; i < Stages.Length; i++)
@@ -80,7 +78,6 @@ private void Startup()
continue;
Stages[i] = (stage.Item1, tileDefinition.TileId);
- _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"Тайл айди {tileDefinition.TileId} для '{stage.Item1}'");
}
_initialized = true;
}
@@ -129,19 +126,15 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
for (int i = 0; i < tilesToReplace; i++)
{
var tilePos = nearbyTiles[i];
- _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"тайл поз {tilePos} грид {grid} {_map.TryGetTile(grid, tilePos, out var tiles)}");
if (!_map.TryGetTile(grid, tilePos, out var tile))
continue;
var stagelast = Stages.Length-1;
- _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"тайл айди {tile.TypeId} длина стейжеса {Stages.Length}");
if (tile.TypeId == Stages[stagelast].Item2)
continue;
- _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"грид2 {i}");
var index = 0;
foreach (var stage in Stages)
{
- _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"грид3 {stage}");
if (stage.Item2 == tile.TypeId)
break;
index++;
@@ -149,7 +142,6 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
if (index == stagelast+1)
index = 0;
_map.SetTile(grid.Owner, grid , tilePos, new Tile(Stages[index+1].Item2, 0, 0));
- _adminlogs.Add(LogType.Trigger, LogImpact.Extreme, $"индекс {index}");
}
if (!TerminatingOrDeleted(args.OtherEntity))
component.HitList.Add(args.OtherEntity);
From 8f2613b015b6790a921c24a6694a1c82e944c5cb Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Fri, 6 Mar 2026 15:49:30 +0300
Subject: [PATCH 06/20] =?UTF-8?q?=D0=B2=D1=8B=D0=B3=D1=80=D1=83=D0=B6?=
=?UTF-8?q?=D0=B0=D0=B5=D0=BC=20=D0=BA=D1=83=D1=87=D1=83=20=D0=B2=D1=81?=
=?UTF-8?q?=D0=B5=D0=B3=D0=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
надо бы это делать по чаще....
---
.../Medieval/Ships/Helm/HelmSystem.cs | 76 +++++
.../Ships/Helm/SteeringOarComponent.cs | 10 +
.../Medieval/Ships/Oar/ServerOarSystem.cs | 166 ++++++++---
.../PlayerDrowning/PlayerDrowningSystem.cs | 23 +-
.../Medieval/Ships/Sail/SailSystem.cs | 175 ++++++-----
.../ShipDrowning/ShipDrowningComponent.cs | 14 +
.../Ships/ShipDrowning/ShipDrowningSystem.cs | 86 ++++++
.../Ships/SummonShip/SummonShipComponent.cs | 17 ++
.../Ships/SummonShip/SummonShipSystem.cs | 63 ++++
.../Medieval/Ships/Wave/WaveSystem.cs | 7 +-
.../Ships/WeatherVane/WeatherVaneComponent.cs | 10 +
.../Administration/Ships/ShipsCCVars.cs | 22 ++
.../Imperial/Medieval/Ships/Oar/OarSystem.cs | 271 +++++++++---------
.../Medieval/Ships/Sail/SailComponent.cs | 8 +-
.../Medieval/Ships/Sail/SailUseEvent.cs | 11 +
.../Medieval/Ships/Sail/SharedSailSystem.cs | 70 +++++
.../Medieval/Ships/Wind/SharedWindSystem.cs | 133 ---------
.../Rotatable/RotatableComponent.cs | 6 +-
.../Prototypes/Imperial/Medieval/decor.yml | 7 +-
19 files changed, 780 insertions(+), 395 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Helm/SteeringOarComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/WeatherVane/WeatherVaneComponent.cs
create mode 100644 Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
rename {Content.Server => Content.Shared}/Imperial/Medieval/Ships/Sail/SailComponent.cs (60%)
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs b/Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs
new file mode 100644
index 00000000000..f248a39cf0b
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs
@@ -0,0 +1,76 @@
+using System.Numerics;
+using Content.Server.Administration.Logs;
+using Content.Shared._RD.Weight.Systems;
+using Content.Shared.Database;
+using Content.Shared.DoAfter;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Imperial.Medieval.Skills;
+using Content.Shared.Popups;
+using NetCord;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Physics.Systems;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Imperial.Medieval.Ships.Helm;
+
+///
+/// This handles...
+///
+public sealed class HelmSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedSkillsSystem _skills = default!;
+ [Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly RDWeightSystem _rdWeight = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IAdminLogManager _adminLog = default!;
+
+ public void RotateShip(EntityUid boat, EntityUid helm, float helmForce)
+ {
+ _physics.WakeBody(boat);
+ var helmAngle = _transform.GetWorldRotation(helm);
+ var entities = _lookup.GetEntitiesIntersecting(boat);
+ EntityUid? steeringOar = null;
+ foreach (var e in entities)
+ {
+ if (HasComp(e))
+ {
+ steeringOar = e;
+ break;
+ }
+ }
+ if (steeringOar == null)
+ return;
+ var steeringOarAngle = _transform.GetWorldRotation(steeringOar.Value);
+ var diff = (float)steeringOarAngle*180 - (float)helmAngle*180;
+ diff *= -1;
+ if (helmForce > 0)
+ {
+ _physics.ApplyAngularImpulse(boat, diff);
+ return;
+ }
+ if (helmForce < 0)
+ {
+ _physics.ApplyAngularImpulse(boat, -diff);
+ return;
+ }
+ }
+
+ public float CheckForce(EntityUid boat, EntityUid helm)
+ {
+ var boatAngle = (float)_transform.GetWorldRotation(boat)*180;
+ var helmcos = MathF.Cos(boatAngle);
+ var helmsin = MathF.Sin(boatAngle);
+ var helmVector = _physics.GetMapLinearVelocity(boat);
+ var helmForce = Math.Abs(helmVector.X) + Math.Abs(helmVector.Y);
+ _adminLog.Add(LogType.Action, LogImpact.Extreme, $"хельма {helmForce}");
+ return helmForce;
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Helm/SteeringOarComponent.cs b/Content.Server/Imperial/Medieval/Ships/Helm/SteeringOarComponent.cs
new file mode 100644
index 00000000000..16c657879f7
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Helm/SteeringOarComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Server.Imperial.Medieval.Ships.Helm;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class SteeringOarComponent : Component
+{
+
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
index b10a30cf05b..3266e03e801 100644
--- a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
@@ -1,36 +1,130 @@
-// using System.Numerics;
-// using Content.Server.Administration.Logs;
-// using Content.Shared.Database;
-// using Content.Shared.DoAfter;
-// using Content.Shared.Imperial.Medieval.Ships.Oar;
-// using Content.Shared.Imperial.Medieval.Skills;
-// using Content.Shared.Interaction;
-// using Content.Shared.Popups;
-// using Robust.Shared.Map;
-// using Robust.Shared.Physics.Components;
-// using Robust.Shared.Physics.Systems;
-// using Robust.Shared.Serialization;
-//
-// namespace Content.Server.Imperial.Medieval.Ships.Oar;
-//
-// ///
-// // /// This handles...
-// ///
-// public sealed class ServerOarSystem : EntitySystem
-// {
-// [Dependency] private readonly SharedPopupSystem _popup = default!;
-// [Dependency] private readonly SharedPhysicsSystem _physics = default!;
-// [Dependency] private readonly SharedTransformSystem _transform = default!;
-// [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
-// [Dependency] private readonly SharedSkillsSystem _skills = default!;
-// [Dependency] private readonly IAdminLogManager _adminLog = default!;
-//
-// public override void Initialize()
-// {
-//
-// }
-//
-//
-//
-//
-// }
+using System.Numerics;
+using Content.Shared._RD.Weight.Components;
+using Content.Shared._RD.Weight.Systems;
+using Content.Shared.Coordinates;
+using Content.Shared.DoAfter;
+using Content.Shared.Imperial.Medieval.Skills;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Popups;
+using Robust.Shared.Physics;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Physics.Systems;
+
+
+using Content.Shared.Database;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Imperial.Medieval.Ships.Oar;
+
+
+namespace Content.Server.Imperial.Medieval.Ships.Oar;
+
+///
+/// This handles...
+///
+public sealed class OarSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedSkillsSystem _skills = default!;
+ [Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly RDWeightSystem _rdWeight = default!;
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnOarAfterInteract);
+ SubscribeLocalEvent(OnOarDoAfter);
+ }
+
+ private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInteractEvent args)
+ {
+ var playerEntity = args.User;
+
+ if (args.Handled || !args.CanReach )
+ return;
+
+ var boat = _transform.GetParentUid(playerEntity);
+
+ if (boat == args.ClickLocation.EntityId)
+ return;
+
+ var clickEntity = args.ClickLocation.EntityId;
+ if (boat == _transform.GetParentUid(clickEntity))
+ return;
+
+ var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
+ var sdoAfter = new DoAfterArgs(EntityManager,
+ playerEntity,
+ time,
+ new OnOarDoAfterEvent(),
+ args.Used,
+ args.Target,
+ args.Used)
+ {
+ MovementThreshold = 0.5f,
+ BreakOnMove = true,
+ CancelDuplicate = true,
+ DistanceThreshold = 2,
+ BreakOnDamage = true,
+ RequireCanInteract = false,
+ BreakOnDropItem = true,
+ BreakOnHandChange = true,
+ };
+ _doAfter.TryStartDoAfter(sdoAfter);
+ var playerPosition = _transform.GetWorldPosition(playerEntity);
+ var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
+ var direction = (playerPosition - boatPosition).Normalized();
+ component.Direction = direction;
+ }
+
+ private void OnOarDoAfter(EntityUid uid, OarComponent component, ref OnOarDoAfterEvent args)
+ {
+ var item = _hands.GetActiveItem(args.User);
+ if (args.Cancelled || args.Handled || item == null)
+ return;
+
+ if (!TryComp(item, out var comp))
+ return;
+
+ Push(item.Value, comp.Direction, comp.Power, args.User);
+ args.Handled = true;
+ args.Repeat = true;
+ }
+
+ private void Push(EntityUid item, Vector2 direction, float power, EntityUid player)
+ {
+ power += power * (10 - _skills.GetSkillLevel(player, "Strength")) * 0.1f;
+
+ var boat = _transform.GetParentUid(player);
+
+ var entities = _lookup.GetEntitiesIntersecting(boat);
+
+ if (entities.Count > 1000)
+ return;
+
+ var weight = _rdWeight.GetTotal(boat);
+
+ foreach (var entity in entities)
+ {
+ if (HasComp(entity))
+ weight += _rdWeight.GetTotal(entity);
+ }
+
+ if (weight == 0)
+ weight = 10;
+ var impulse = direction * (power / weight);
+ var angleimpulse = (power / weight);
+ if (direction.X < 0)
+ angleimpulse = -angleimpulse;
+
+ if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
+ {
+ _physics.WakeBody(boat);
+ _physics.ApplyLinearImpulse(boat, impulse, body: body);
+ _physics.ApplyAngularImpulse(boat, angleimpulse, body: body);
+ }
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
index 1f0c1caa786..176bd6e6818 100644
--- a/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/PlayerDrowning/PlayerDrowningSystem.cs
@@ -42,15 +42,26 @@ public override void Update(float frameTime)
foreach (var component in EntityManager.EntityQuery())
{
if (!TryComp(component.Owner, out var transform))
- return;
- var childs = new List();
- var childEnum = transform.ChildEnumerator;
- while (childEnum.MoveNext(out var child))
+ continue;
+ var childBasement = transform.ChildEnumerator;
+ while (childBasement.MoveNext(out var childUid))
+ EnsureComp(childUid);
+ }
+
+ foreach (var component in EntityManager.EntityQuery())
+ {
+ if (HasComp(_transform.GetParentUid(component.Owner)))
{
- ProcessDrowning(child);
+ ProcessDrowning(component.Owner);
+ continue;
}
+ if (component.DrownTime > 0)
+ component.DrownTime -= 1;
+ else
+ RemComp(component.Owner);
}
+
}
}
@@ -76,7 +87,7 @@ private void ProcessDrowning(EntityUid uid)
return;
}
- if (_staminaSystem.TryTakeStamina(uid, 25, ignoreResist: true))
+ if (_staminaSystem.TryTakeStamina(uid, 10, ignoreResist: true))
return;
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
index 23c5be2cd95..c6b8065f952 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -1,15 +1,25 @@
using System.Numerics;
+using Content.Server.Administration.Logs;
+using Content.Server.Imperial.Medieval.Ships.Helm;
+using Content.Server.Imperial.Medieval.Ships.ShipDrowning;
+using Content.Server.Imperial.Medieval.Ships.WeatherVane;
using Content.Shared._RD.Weight.Components;
using Content.Shared._RD.Weight.Systems;
+using Content.Shared.Changeling;
+using Content.Shared.Database;
using Content.Shared.DoAfter;
using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Imperial.Medieval.Administration.Ships;
+using Content.Shared.Imperial.Medieval.Ships.Sail;
using Content.Shared.Imperial.Medieval.Ships.Wind;
using Content.Shared.Imperial.Medieval.Skills;
using Content.Shared.Popups;
+using Robust.Shared.Configuration;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
using Robust.Shared.Timing;
+using Robust.Shared.Maths;
namespace Content.Server.Imperial.Medieval.Ships.Sail;
@@ -29,12 +39,13 @@ public sealed class SailSystem : EntitySystem
[Dependency] private readonly RDWeightSystem _rdWeight = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IAdminLogManager _adminLog = default!;
+ [Dependency] private readonly HelmSystem _helm = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
- private const float DefaultReloadTimeSeconds = 1f;
private TimeSpan _nextCheckTime;
- private int _windForce;
- private int _windAngle;
+
///
public override void Initialize()
{
@@ -48,21 +59,13 @@ public override void Update(float frameTime)
if (curTime > _nextCheckTime)
{
- _nextCheckTime = curTime + TimeSpan.FromSeconds(DefaultReloadTimeSeconds);
-
- // Плавные изменения ветра (0–10)
- if (_windForce <= 0)
- _windForce += _random.Next(0, 2);
- else if (_windForce >= 10)
- _windForce -= _random.Next(0, 2);
- else
- _windForce += _random.Next(-1, 2);
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(_cfg.GetCVar(ShipsCCVars.WindChangeTime));
- // Угол ветра: -45° до +45° (в градусах) — реалистично для моря
- _windAngle += _random.Next(-5, 6); // ±5 градусов за шаг
- _windAngle = Math.Clamp(_windAngle, -45, 45);
+ RandomiseVind();
- // --- Обработка каждого паруса ---
+ var ships = new List();
+ var windAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
+ var windForce = _cfg.GetCVar(ShipsCCVars.WindPower);
foreach (var sailComponent in EntityManager.EntityQuery())
{
if (sailComponent.Folded)
@@ -70,77 +73,57 @@ public override void Update(float frameTime)
var sailEntity = sailComponent.Owner;
var boat = _transform.GetParentUid(sailEntity);
- if (!EntityManager.TryGetComponent(boat, out PhysicsComponent? boatBody))
- continue;
+ EnsureComp(boat);
+ var boatAngle = new Angle();
+ var entities = _lookup.GetEntitiesIntersecting(boat);
+ foreach (var entity in entities)
+ {
+ if (HasComp(entity))
+ boatAngle = _transform.GetWorldRotation(entity);
+
+ }
+
+ var sailAngle = (float)_transform.GetWorldRotation(sailEntity)*180;
- // Получаем углы в радианах
- float sailAngleRad = (float)_transform.GetWorldRotation(sailEntity).Theta;
- float boatAngleRad = (float)_transform.GetWorldRotation(boat).Theta;
- float windAngleRad = _windAngle * MathF.PI / 180f; // ветер в радианах
-
- // Направление ветра как вектор
- Vector2 windDirection = new Vector2(
- MathF.Cos(windAngleRad),
- MathF.Sin(windAngleRad)
- );
-
- // Нормаль паруса — перпендикуляр к его поверхности (наружу)
- // Парус — плоскость, нормаль — направление, в которое он "ловит" ветер
- var sailNormalAngleRad = sailAngleRad + MathF.PI / 2f;
- var sailNormal = new Vector2(
- MathF.Cos(sailNormalAngleRad),
- MathF.Sin(sailNormalAngleRad)
- );
-
- // Угол между ветром и нормалью паруса
- var dot = Math.Clamp(Vector2.Dot(windDirection, sailNormal), -1f, 1f);
- var angleBetween = MathF.Acos(dot);
-
- // Эффективность: максимальна, когда ветер перпендикулярен парусу (0°)
- // Минимальна, когда ветер параллелен (90°+)
- var efficiency = MathF.Cos(angleBetween);
-
- // Если ветер дует сзади (угол > 90°), всё равно даём слабую тягу
- // (реальные паруса могут работать и на "бейсинге")
- if (angleBetween > MathF.PI / 2f)
- efficiency = MathF.Max(0.05f, efficiency); // 5% тяги сзади
- else
- efficiency = MathF.Max(0f, efficiency);
-
- // Сила ветра = базовая сила × площадь × эффективность
- var forceMagnitude = _windForce * sailComponent.SailSize * efficiency;
-
- // Направление силы — вдоль нормали паруса
- var forceDirection = sailNormal * forceMagnitude;
-
- // Крутящий момент: сила × плечо × sin(разница между парусом и кораблём)
- // Плечо — расстояние от центра корабля до центра паруса (условное)
- var sailOffset = 0.5f; // метры — можно настроить в компоненте
- var torqueFactor = MathF.Sin(sailAngleRad - boatAngleRad); // как сильно парус "выступает" вбок
- var torque = forceMagnitude * sailOffset * torqueFactor * 0.1f; // масштабируем
-
- var windEffect = new WindEffect
+ while ( Math.Abs(sailAngle) > 360)
{
- PushForce = forceDirection,
- RotationTorque = torque
- };
+ if (sailAngle > 0)
+ sailAngle -= 360;
+ else
+ sailAngle += 360;
+ }
- Push(sailEntity, sailComponent, windEffect);
+ while ( Math.Abs(sailAngle) > 360)
+ {
+ if (sailAngle > 0)
+ sailAngle -= 360;
+ else
+ sailAngle += 360;
+ }
+
+ var diffAngle = sailAngle - windAngle;
+ var force = windForce * MathF.Cos(diffAngle/180) * sailComponent.SailSize;
+
+ Push(sailEntity, force, boatAngle , push: sailComponent.Push, helm: sailComponent.Helm);
+ if (!ships.Contains(boat))
+ ships.Add(boat);
}
}
}
- private void Push(EntityUid sail, SailComponent sailComponent, WindEffect windForce)
+ private void Push(EntityUid sail, float windForce, Angle torque , bool push = true, bool helm = false)
{
var boat = _transform.GetParentUid(sail);
+ var boatAngle = _transform.GetWorldRotation(boat);
+
+ var weight = _rdWeight.GetTotal(boat);
+
var entities = _lookup.GetEntitiesIntersecting(boat);
- if (entities.Count > 1000)
+ if (entities.Count > 1000000)
return;
- var weight = _rdWeight.GetTotal(boat);
-
foreach (var entity in entities)
{
if (HasComp(entity))
@@ -149,13 +132,47 @@ private void Push(EntityUid sail, SailComponent sailComponent, WindEffect windFo
if (weight == 0)
weight = 10;
- var impulse = windForce.PushForce;
- var angleimpulse = windForce.RotationTorque;
- if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
+ torque += Angle.FromDegrees(90);
+ if (windForce < 0)
+ windForce *= (float)0.5;
+ var impulse = torque.ToVec() * windForce;
+ if (!push)
{
- _physics.WakeBody(boat);
- _physics.ApplyLinearImpulse(boat, impulse, body: body);
- _physics.ApplyAngularImpulse(boat, angleimpulse);
+ _transform.SetWorldRotation(sail, Angle.FromDegrees(_cfg.GetCVar(ShipsCCVars.WindRotation)));
}
+
+ if (helm)
+ _helm.RotateShip(boat,sail, _helm.CheckForce(boat, sail));
+
+ if (_helm.CheckForce(boat, sail) > _cfg.GetCVar(ShipsCCVars.ShipsMaxSpeed))
+ return;
+
+ _physics.ApplyLinearImpulse(boat, impulse);
+ }
+
+ private void RandomiseVind()
+ {
+
+
+
+ // ветерок сила
+ var windForce = _cfg.GetCVar(ShipsCCVars.WindPower);
+ if (windForce <= 0)
+ windForce += _random.Next(0, 2);
+ else if (windForce >= 10)
+ windForce -= _random.Next(0, 2);
+ else
+ windForce += _random.Next(-1, 2);
+ _cfg.SetCVar(ShipsCCVars.WindPower, windForce);
+
+ // ветерок направление
+ var windAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
+ windAngle += _random.Next(-1, 2)*5; // ±5 градусов за шаг
+ if (Math.Abs(windAngle) > 360)
+ windAngle = 0;
+ else if (windAngle < 0)
+ windAngle += 360;
+
+ _cfg.SetCVar(ShipsCCVars.WindRotation, windAngle);
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs b/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
new file mode 100644
index 00000000000..6345057a131
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
@@ -0,0 +1,14 @@
+namespace Content.Server.Imperial.Medieval.Ships.ShipDrowning;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class ShipDrowningComponent : Component
+{
+ [DataField("DrownLevel")]
+ public int DrownLevel;
+
+ [DataField("DrownMaxLevel")]
+ public float DrownMaxLevel = 10000000000;
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs b/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs
new file mode 100644
index 00000000000..8a09ad07dfd
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs
@@ -0,0 +1,86 @@
+using System.Linq;
+using Content.Server.Administration.Commands;
+using Content.Server.Imperial.Medieval.Ships.PlayerDrowning;
+using Content.Server.Imperial.Medieval.Ships.Wave;
+using Content.Shared.Damage;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Imperial.Medieval.Ships.ShipDrowning;
+
+///
+/// This handles...
+///
+public sealed class ShipDrowningSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly EntityManager _entityManager = default!;
+ [Dependency] private readonly SharedMapSystem _map = default!;
+ [Dependency] private readonly WaveSystem _wave = default!;
+
+ private const float DefaultReloadTimeSeconds = 10f;
+ public const string ConductorContainer = "Conductor";
+
+ private TimeSpan _nextCheckTime;
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+ _nextCheckTime = _timing.CurTime + TimeSpan.FromSeconds(DefaultReloadTimeSeconds);
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var curTime = _timing.CurTime;
+
+ if (curTime > _nextCheckTime)
+ {
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(DefaultReloadTimeSeconds);
+
+ foreach (var component in EntityManager.EntityQuery())
+ {
+ var ship = component.Owner;
+
+ if (component.DrownLevel > component.DrownMaxLevel)
+ {
+ if (component.DrownLevel > component.DrownMaxLevel * 10)
+ {
+ _entityManager.DeleteEntity(ship);
+ return;
+ }
+ EnsureComp(ship);
+ return;
+ }
+ if (HasComp(ship))
+ RemComp(ship);
+
+ if (!TryComp(ship, out var mapGrid))
+ return;
+ var allTilesEnumerator = _map.GetAllTilesEnumerator(ship, mapGrid);
+
+ var brokenTilesCount = 0;
+ var allTilesCount = 0;
+ var brokenlevel = 0;
+
+ while (allTilesEnumerator.MoveNext(out var tile))
+ {
+ allTilesCount++;
+ brokenlevel = 0;
+ foreach (var stage in _wave.Stages)
+ {
+ if (stage.Item2 == tile.Value.Tile.TypeId)
+ brokenTilesCount+= brokenlevel;
+ brokenlevel++;
+ }
+ }
+
+ component.DrownLevel += brokenTilesCount;
+ component.DrownMaxLevel = allTilesCount * 100;
+ }
+
+ }
+
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipComponent.cs b/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipComponent.cs
new file mode 100644
index 00000000000..3c384b578c3
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipComponent.cs
@@ -0,0 +1,17 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Imperial.Medieval.Ships.SummonShip;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class SummonShipComponent : Component
+{
+ [DataField(required: true, customTypeSerializer:typeof(PrototypeIdSerializer))]
+ public string File = "/Ships/Victoria.yml";
+
+ [DataField]
+ public float Delay = 2;
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs b/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs
new file mode 100644
index 00000000000..d0ea8da6673
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs
@@ -0,0 +1,63 @@
+using System.IO;
+using Content.Server.Administration.Logs;
+using Content.Shared.Database;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Timing;
+using Robust.Shared.ContentPack;
+using Robust.Shared.EntitySerialization.Systems;
+using Robust.Shared.Map;
+using Robust.Shared.Physics.Systems;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.Manager;
+using Robust.Shared.Timing;
+using Robust.Shared.Utility;
+
+namespace Content.Server.Imperial.Medieval.Ships.SummonShip;
+
+///
+/// This handles...
+///
+public sealed class SummonShipSystem : EntitySystem
+{
+
+ [Dependency] private readonly MapLoaderSystem _mapLoader = default!;
+ [Dependency] private readonly IMapManager _mapMan = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly IAdminLogManager _adminLog = default!;
+ [Dependency] private readonly IPrototypeManager _prototype = default!;
+ [Dependency] private readonly UseDelaySystem _delay = default!;
+
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnUse);
+ }
+
+ private void OnUse(EntityUid uid, SummonShipComponent comp, UseInHandEvent args)
+ {
+ if (args.Handled)
+ return;
+ args.Handled = true;
+ var time = TimeSpan.FromSeconds(comp.Delay);
+ _delay.SetLength(uid, time);
+ Timer.Spawn(time, () => Use(uid, comp));
+ }
+
+ private void Use(EntityUid uid, SummonShipComponent comp)
+ {
+ var mapId = _transform.GetMapId(uid);
+ var worldPos = _transform.GetWorldPosition(uid);
+
+ var path = new ResPath(comp.File);
+
+ if (!_mapLoader.TryLoadGrid(mapId, path, out var grid, offset: worldPos))
+ {
+ _adminLog.Add(LogType.Action, LogImpact.High, $"Ошибка Загрузки грида из {path} сущность загрузки {uid}");
+ return;
+ }
+
+ EntityManager.QueueDeleteEntity(uid);
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index fb279ed4aa2..59d098d24ec 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -54,7 +54,7 @@ public sealed class WaveSystem : EntitySystem
("Plating", (ushort)3),
("FloorWhite", (ushort)4)
};
- private const float RadiusTiles = 2f;
+ private const float RadiusTiles = 3f;
private bool _initialized;
public override void Initialize()
@@ -96,13 +96,16 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
if (!_entityManager.TryGetComponent(gridEntity, out var mapGridComp))
return;
-
var grid = new Entity(gridEntity, mapGridComp);
+
var tileRef = _map.GetTileRef(grid, collisionPos);
+
var centerTilePos = _map.MapToGrid(grid, collisionPos);
var antiradius = (int)RadiusTiles*-1;
+
var nearbyTiles = new List();
+
for (int dx = antiradius; dx <= RadiusTiles; dx++)
{
for (int dy = antiradius; dy <= RadiusTiles; dy++)
diff --git a/Content.Server/Imperial/Medieval/Ships/WeatherVane/WeatherVaneComponent.cs b/Content.Server/Imperial/Medieval/Ships/WeatherVane/WeatherVaneComponent.cs
new file mode 100644
index 00000000000..f7fed230b40
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/WeatherVane/WeatherVaneComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Server.Imperial.Medieval.Ships.WeatherVane;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class WeatherVaneComponent : Component
+{
+
+}
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
new file mode 100644
index 00000000000..6ec2ba1036e
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -0,0 +1,22 @@
+using Robust.Shared;
+using Robust.Shared.Configuration;
+namespace Content.Shared.Imperial.Medieval.Administration.Ships;
+
+///
+/// Цвары для корабликов, тут лежит ветер максимальная скорость кораблей и подобное
+///
+[CVarDefs]
+public sealed class ShipsCCVars : CVars
+{
+ public static readonly CVarDef ShipsMaxSpeed =
+ CVarDef.Create("ships.maxspeed", 20f, CVar.REPLICATED | CVar.SERVER);
+
+ public static readonly CVarDef WindChangeTime =
+ CVarDef.Create("ships.windchangetime", 1f, CVar.REPLICATED | CVar.SERVER);
+
+ public static readonly CVarDef WindPower =
+ CVarDef.Create("ships.windpower", 1f, CVar.REPLICATED | CVar.SERVER);
+ public static readonly CVarDef WindRotation =
+ CVarDef.Create("ships.windrotation", 0f, CVar.REPLICATED | CVar.SERVER);
+}
+
diff --git a/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
index 0df7cb2eb35..bbd88a65065 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
@@ -1,134 +1,137 @@
-using System.Numerics;
-using Content.Shared._RD.Weight.Components;
-using Content.Shared._RD.Weight.Systems;
-using Content.Shared.Coordinates;
-using Content.Shared.DoAfter;
-using Content.Shared.Imperial.Medieval.Skills;
-using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
-using Content.Shared.Popups;
-using Robust.Shared.Physics;
-using Robust.Shared.Physics.Components;
-using Robust.Shared.Physics.Systems;
-
-
-using Content.Shared.Database;
-using Content.Shared.Hands.EntitySystems;
-
-
-namespace Content.Shared.Imperial.Medieval.Ships.Oar;
-
-///
-/// This handles...
-///
-public sealed class OarSystem : EntitySystem
-{
- [Dependency] private readonly SharedPopupSystem _popup = default!;
- [Dependency] private readonly SharedPhysicsSystem _physics = default!;
- [Dependency] private readonly SharedTransformSystem _transform = default!;
- [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
- [Dependency] private readonly SharedSkillsSystem _skills = default!;
- [Dependency] private readonly EntityManager _entManager = default!;
- [Dependency] private readonly EntityLookupSystem _lookup = default!;
- [Dependency] private readonly SharedHandsSystem _hands = default!;
- [Dependency] private readonly RDWeightSystem _rdWeight = default!;
- public override void Initialize()
- {
- SubscribeLocalEvent(OnOarAfterInteract);
- SubscribeLocalEvent(OnOarDoAfter);
- }
-
- private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInteractEvent args)
- {
- var playerEntity = args.User;
-
- if (args.Handled || !args.CanReach )
- return;
-
- bool foundWater = false;
- foreach (var entity in _lookup.GetEntitiesInRange(args.ClickLocation, 0.3f))
- {
- if (MetaData(entity).EntityPrototype?.ID == "MedievalWaterDeepDarkEntity")
- {
- foundWater = true;
- break;
- }
- }
- if (!foundWater)
- return;
-
- var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
- var sdoAfter = new DoAfterArgs(EntityManager,
- playerEntity,
- time,
- new OnOarDoAfterEvent(),
- args.Target,
- target: args.Used)
- {
- MovementThreshold = 0.5f,
- BreakOnMove = true,
- CancelDuplicate = true,
- DistanceThreshold = 2,
- BreakOnDamage = true,
- RequireCanInteract = false,
- BreakOnDropItem = true,
- BreakOnHandChange = true,
- };
- if (!_doAfter.TryStartDoAfter(sdoAfter))
- return;
-
- var playerPosition = _transform.GetWorldPosition(playerEntity);
- var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
- var direction = (playerPosition - boatPosition).Normalized();
- component.Direction = direction;
- args.Handled = true;
-
- }
-
- private void OnOarDoAfter(EntityUid uid, MetaDataComponent component, OnOarDoAfterEvent args)
- {
- var item = _hands.GetActiveItem(args.User);
- if (args.Cancelled || args.Handled || item == null)
- return;
-
- if (!TryComp(item, out var comp))
- return;
-
- Push(item.Value, comp.Direction, comp.Power, args.User);
- args.Handled = true;
- }
-
- private void Push(EntityUid item, Vector2 direction, float power, EntityUid player)
- {
- power += power * (10 - _skills.GetSkillLevel(player, "Strength")) * 0.1f;
-
- var boat = _transform.GetParentUid(player);
-
- var entities = _lookup.GetEntitiesIntersecting(boat);
-
- if (entities.Count > 1000)
- return;
-
- var weight = _rdWeight.GetTotal(boat);
-
- foreach (var entity in entities)
- {
- if (HasComp(entity))
- weight += _rdWeight.GetTotal(entity);
- }
-
- if (weight == 0)
- weight = 10;
- var impulse = direction * (power / weight);
- var angleimpulse = (power / weight);
- if (direction.X < 0)
- angleimpulse = -angleimpulse;
-
- if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
- {
- _physics.WakeBody(boat);
- _physics.ApplyLinearImpulse(boat, impulse, body: body);
- _physics.ApplyAngularImpulse(boat, angleimpulse);
- }
- }
-}
+// using System.Numerics;
+// using Content.Shared._RD.Weight.Components;
+// using Content.Shared._RD.Weight.Systems;
+// using Content.Shared.Coordinates;
+// using Content.Shared.DoAfter;
+// using Content.Shared.Imperial.Medieval.Skills;
+// using Content.Shared.Interaction;
+// using Content.Shared.Interaction.Events;
+// using Content.Shared.Popups;
+// using Robust.Shared.Physics;
+// using Robust.Shared.Physics.Components;
+// using Robust.Shared.Physics.Systems;
+//
+//
+// using Content.Shared.Database;
+// using Content.Shared.Hands.EntitySystems;
+//
+//
+// namespace Content.Shared.Imperial.Medieval.Ships.Oar;
+//
+// ///
+// /// По идее это должно быть тут, но млять грёбаный делей
+// ///
+// public sealed class OarSystem : EntitySystem
+// {
+// [Dependency] private readonly SharedPopupSystem _popup = default!;
+// [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+// [Dependency] private readonly SharedTransformSystem _transform = default!;
+// [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+// [Dependency] private readonly SharedSkillsSystem _skills = default!;
+// [Dependency] private readonly EntityManager _entManager = default!;
+// [Dependency] private readonly EntityLookupSystem _lookup = default!;
+// [Dependency] private readonly SharedHandsSystem _hands = default!;
+// [Dependency] private readonly RDWeightSystem _rdWeight = default!;
+// public override void Initialize()
+// {
+// SubscribeLocalEvent(OnOarAfterInteract);
+// SubscribeLocalEvent(OnOarDoAfter);
+// }
+//
+// private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInteractEvent args)
+// {
+// var playerEntity = args.User;
+//
+// if (args.Handled || !args.CanReach )
+// return;
+//
+//
+// var boat = _transform.GetParentUid(playerEntity);
+//
+//
+// if (boat == args.ClickLocation.EntityId)
+// return;
+//
+// var clickEntity = args.ClickLocation.EntityId;
+// if (boat == _transform.GetParentUid(clickEntity))
+// return;
+//
+// var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
+// var sdoAfter = new DoAfterArgs(EntityManager,
+// playerEntity,
+// time,
+// new OnOarDoAfterEvent(),
+// args.Target,
+// target: args.Used)
+// {
+// MovementThreshold = 0.5f,
+// BreakOnMove = true,
+// CancelDuplicate = true,
+// DistanceThreshold = 2,
+// BreakOnDamage = true,
+// RequireCanInteract = false,
+// BreakOnDropItem = true,
+// BreakOnHandChange = true,
+// };
+//
+//
+// _popup.PopupClient(Loc.GetString($"{playerEntity} {time} {args.Target} {args.Used}"), component.Owner, args.User);
+// _doAfter.TryStartDoAfter(sdoAfter);
+//
+//
+//
+//
+// var playerPosition = _transform.GetWorldPosition(playerEntity);
+// var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
+// var direction = (playerPosition - boatPosition).Normalized();
+// component.Direction = direction;
+// }
+//
+// private void OnOarDoAfter(EntityUid uid, OarComponent component, ref OnOarDoAfterEvent args)
+// {
+// var item = _hands.GetActiveItem(args.User);
+// if (args.Cancelled || args.Handled || item == null)
+// return;
+//
+// if (!TryComp(item, out var comp))
+// return;
+//
+// Push(item.Value, comp.Direction, comp.Power, args.User);
+// args.Handled = true;
+// args.Repeat = true;
+// }
+//
+// private void Push(EntityUid item, Vector2 direction, float power, EntityUid player)
+// {
+// power += power * (10 - _skills.GetSkillLevel(player, "Strength")) * 0.1f;
+//
+// var boat = _transform.GetParentUid(player);
+//
+// var entities = _lookup.GetEntitiesIntersecting(boat);
+//
+// if (entities.Count > 1000)
+// return;
+//
+// var weight = _rdWeight.GetTotal(boat);
+//
+// foreach (var entity in entities)
+// {
+// if (HasComp(entity))
+// weight += _rdWeight.GetTotal(entity);
+// }
+//
+// if (weight == 0)
+// weight = 10;
+// var impulse = direction * (power / weight);
+// var angleimpulse = (power / weight);
+// if (direction.X < 0)
+// angleimpulse = -angleimpulse;
+//
+// if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
+// {
+// _physics.WakeBody(boat);
+// _physics.ApplyLinearImpulse(boat, impulse, body: body);
+// _physics.ApplyAngularImpulse(boat, angleimpulse, body: body);
+// }
+// }
+// }
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailComponent.cs b/Content.Shared/Imperial/Medieval/Ships/Sail/SailComponent.cs
similarity index 60%
rename from Content.Server/Imperial/Medieval/Ships/Sail/SailComponent.cs
rename to Content.Shared/Imperial/Medieval/Ships/Sail/SailComponent.cs
index 631cf37f887..4c5331dee8a 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailComponent.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Sail/SailComponent.cs
@@ -1,4 +1,4 @@
-namespace Content.Server.Imperial.Medieval.Ships.Sail;
+namespace Content.Shared.Imperial.Medieval.Ships.Sail;
///
/// This is used for...
@@ -11,4 +11,10 @@ public sealed partial class SailComponent : Component
[DataField("Folded")]
public bool Folded;
+
+ [DataField("Helm")]
+ public bool Helm;
+
+ [DataField("Push")]
+ public bool Push = true;
}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs b/Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs
new file mode 100644
index 00000000000..08edcb90019
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs
@@ -0,0 +1,11 @@
+using Content.Shared.DoAfter;
+
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Imperial.Medieval.Ships.Sail;
+
+
+[Serializable, NetSerializable]
+public sealed partial class SailUseEvent : SimpleDoAfterEvent
+{
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs
new file mode 100644
index 00000000000..bf6d8b23206
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs
@@ -0,0 +1,70 @@
+using Content.Shared.DoAfter;
+using Content.Shared.Imperial.Medieval.Administration.Ships;
+using Content.Shared.Imperial.Medieval.Ships.Oar;
+using Content.Shared.Imperial.Medieval.Skills;
+using Content.Shared.Interaction;
+using Robust.Shared.Configuration;
+using Robust.Shared.Random;
+
+namespace Content.Shared.Imperial.Medieval.Ships.Sail;
+
+///
+/// вращяет парус по ветру
+///
+public sealed class SharedSailSystem : EntitySystem
+{
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly SharedSkillsSystem _skills = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnActivate);
+ SubscribeLocalEvent(OnInteractUsing);
+ SubscribeLocalEvent(OnUse);
+ }
+
+ private void OnActivate(EntityUid uid, SailComponent component, ActivateInWorldEvent args)
+ {
+ UseDelay(args.User, args.Target);
+ }
+
+ private void OnInteractUsing(EntityUid uid, SailComponent component, InteractUsingEvent args)
+ {
+ UseDelay(args.User, args.Target);
+ }
+
+ private void UseDelay(EntityUid playerEntity, EntityUid targetEntity)
+ {
+
+ var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
+ var sdoAfter = new DoAfterArgs(EntityManager,
+ playerEntity,
+ time,
+ new SailUseEvent(),
+ targetEntity,
+ playerEntity)
+ {
+ MovementThreshold = 0.5f,
+ BreakOnMove = true,
+ CancelDuplicate = true,
+ DistanceThreshold = 2,
+ BreakOnDamage = true,
+ RequireCanInteract = false,
+ BreakOnDropItem = true,
+ BreakOnHandChange = true,
+ };
+ _doAfter.TryStartDoAfter(sdoAfter);
+ }
+
+ private void OnUse(EntityUid uid, SailComponent component, SailUseEvent args)
+ {
+ Rotate(uid);
+ }
+
+ private void Rotate(EntityUid uid)
+ {
+ _transform.SetWorldRotation(uid, _cfg.GetCVar(ShipsCCVars.WindRotation)/180);
+ }
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs
index 6f8990921b8..40e9eea46d4 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Wind/SharedWindSystem.cs
@@ -13,139 +13,6 @@ public override void Initialize()
{
// Initialization logic here if needed
}
-
- ///
- /// Calculates the aerodynamic forces acting on a sail due to wind.
- ///
- /// World position of the ship.
- /// Current rotation of the ship in radians.
- /// Angle of the sail relative to the ship's orientation (radians).
- /// Effective area of the sail (m²).
- /// Current time for dynamic wind simulation.
- /// Density of air (default: 1.2 kg/m³).
- /// A containing force, torque, and wind data.
- public static WindEffect CalculateWindForce(
- Vector2 shipPosition,
- float shipRotation,
- float sailAngle,
- float sailArea,
- float time = 0f,
- float airDensity = 1.2f)
- {
- // Get wind vector at ship's position
- var windVector = GetWindField(shipPosition, time);
- var windStrength = windVector.Length();
- var windDirection = windVector.Normalized();
-
- // Absolute sail angle in world coordinates
- var absoluteSailAngle = shipRotation + sailAngle;
-
- // Angle between wind direction and sail normal
- var windAngle = MathF.Atan2(windDirection.Y, windDirection.X);
- var angleDiff = absoluteSailAngle - windAngle;
- var angleOfAttack = NormalizeAngle(angleDiff);
-
- // Lift and drag coefficients based on angle of attack
- var liftCoefficient = MathF.Sin(2f * angleOfAttack);
- var dragCoefficient = MathF.Abs(MathF.Cos(angleOfAttack));
-
- // Dynamic pressure
- var dynamicPressure = 0.5f * airDensity * windStrength * windStrength;
-
- // Force magnitudes
- var liftForce = liftCoefficient * dynamicPressure * sailArea;
- var dragForce = dragCoefficient * dynamicPressure * sailArea;
-
- // Sail orientation vectors
- Vector2 sailDirection = new(MathF.Cos(absoluteSailAngle), MathF.Sin(absoluteSailAngle)); // Along sail
- Vector2 sailNormal = new(-MathF.Sin(absoluteSailAngle), MathF.Cos(absoluteSailAngle)); // Perpendicular to sail
-
- // Force components
- var liftVector = sailNormal * liftForce;
- var dragVector = sailDirection * dragForce;
-
- // Total force
- var totalForce = liftVector + dragVector;
-
- // Torque calculation
- var leverArm = 1f; // Distance from center of mass to sail (can be parameterized)
- var torque = CalculateTorque(totalForce, absoluteSailAngle, leverArm);
-
- return new WindEffect
- {
- PushForce = totalForce,
- RotationTorque = angleDiff,
- WindStrength = windStrength,
- WindDirection = windDirection
- };
- }
-
- ///
- /// Normalizes an angle to the range [-π, π]
- ///
- private static float NormalizeAngle(float angle)
- {
- while (angle > MathF.PI)
- angle -= MathF.Tau;
- while (angle < -MathF.PI)
- angle += MathF.Tau;
- return angle;
- }
-
- ///
- /// Simple procedural wind field simulation
- ///
- private static Vector2 GetWindField(Vector2 position, float time = 0f)
- {
- var x = position.X;
- var y = position.Y;
-
- var u = MathF.Sin(x / 2f + time) * MathF.Cos(y / 3f) + 0.5f * MathF.Sin(x / 5f + y / 7f);
- var v = MathF.Cos(x / 3f + time) * MathF.Sin(y / 2f) + 0.5f * MathF.Cos(x / 7f - y / 5f);
-
- return new Vector2(u, v);
- }
-
- ///
- /// Calculates rotational torque applied by wind force
- ///
- private static float CalculateTorque(Vector2 force, float sailAngle, float leverArm)
- {
- if (force.LengthSquared() < 0.001f)
- return 0f;
-
- var forceDirection = force.Normalized();
- Vector2 leverDirection = new(-MathF.Sin(sailAngle), MathF.Cos(sailAngle));
-
- // Cross product in 2D: F × r
- var crossProduct = forceDirection.X * leverDirection.Y - forceDirection.Y * leverDirection.X;
-
- return force.Length() * leverArm * crossProduct;
- }
}
-///
-/// Represents the effect of wind on a sail.
-///
-public struct WindEffect
-{
- ///
- /// Net force applied to the ship in world coordinates.
- ///
- public Vector2 PushForce;
-
- ///
- /// Rotational torque around the ship's center.
- ///
- public float RotationTorque;
- ///
- /// Magnitude of the wind vector at this point.
- ///
- public float WindStrength;
-
- ///
- /// Direction of the wind (normalized).
- ///
- public Vector2 WindDirection;
-}
diff --git a/Content.Shared/Rotatable/RotatableComponent.cs b/Content.Shared/Rotatable/RotatableComponent.cs
index 336c484d8c0..c13cc1425f0 100644
--- a/Content.Shared/Rotatable/RotatableComponent.cs
+++ b/Content.Shared/Rotatable/RotatableComponent.cs
@@ -11,18 +11,18 @@ public sealed partial class RotatableComponent : Component
///
/// If true, this entity can be rotated even while anchored.
///
- [DataField, AutoNetworkedField]
+ [DataField("RotateWhileAnchored"), AutoNetworkedField]
public bool RotateWhileAnchored;
///
/// If true, will rotate entity in players direction when pulled
///
- [DataField, AutoNetworkedField]
+ [DataField("RotateWhilePulling"), AutoNetworkedField]
public bool RotateWhilePulling = true;
///
/// The angular value to change when using the rotate verbs.
///
- [DataField, AutoNetworkedField]
+ [DataField("Increment"), AutoNetworkedField]
public Angle Increment = Angle.FromDegrees(90);
}
diff --git a/Resources/Prototypes/Imperial/Medieval/decor.yml b/Resources/Prototypes/Imperial/Medieval/decor.yml
index 9dab0528e5e..54cc2edf8b4 100644
--- a/Resources/Prototypes/Imperial/Medieval/decor.yml
+++ b/Resources/Prototypes/Imperial/Medieval/decor.yml
@@ -5022,7 +5022,7 @@
fixtures:
fix1: #vertical
shape:
- !type:PhysShapeAabb
+ !type:PhysShapeAabb
bounds: "-0.49,-0.15,0.49,0.15"
density: 1000
mask:
@@ -5385,6 +5385,11 @@
layer:
- WallLayer
- type: InteractionOutline
+ - type: Sail
+ SailSize: 5
+ - type: Rotatable
+ RotateWhileAnchored: true
+ Increment: 5
- type: entity
name: small light
From d6ba313b727faf22daa13b01ee39d60e9678a53c Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Fri, 6 Mar 2026 17:37:58 +0300
Subject: [PATCH 07/20] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=D1=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
фиксы
---
.../ShipDrowning/ClientShipDrowningSystem.cs | 3 +++
.../Medieval/Ships/Sail/SailSystem.cs | 1 +
.../ShipDrowning/ShipDrowningComponent.cs | 14 -------------
.../Ships/ShipDrowning/ShipDrowningSystem.cs | 2 +-
.../Medieval/Ships/Storm/StormSystem.cs | 13 ++++++++++++
.../ShipDrowning/ShipDrowningComponent.cs | 21 +++++++++++++++++++
6 files changed, 39 insertions(+), 15 deletions(-)
create mode 100644 Content.Client/Imperial/Medieval/ShipDrowning/ClientShipDrowningSystem.cs
delete mode 100644 Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
diff --git a/Content.Client/Imperial/Medieval/ShipDrowning/ClientShipDrowningSystem.cs b/Content.Client/Imperial/Medieval/ShipDrowning/ClientShipDrowningSystem.cs
new file mode 100644
index 00000000000..3aa059d0fc5
--- /dev/null
+++ b/Content.Client/Imperial/Medieval/ShipDrowning/ClientShipDrowningSystem.cs
@@ -0,0 +1,3 @@
+// тут мог бы быть ваш код)
+// но я криворукий бэкэндер который в душе не чает как работать нормально с визуалом поэтому тут пусто
+// TODO : сделать нормальное отображение потопления, а не тот костыль который я сделаю
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
index c6b8065f952..c28c5ee8eb7 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -11,6 +11,7 @@
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Imperial.Medieval.Administration.Ships;
using Content.Shared.Imperial.Medieval.Ships.Sail;
+using Content.Shared.Imperial.Medieval.Ships.ShipDrowning;
using Content.Shared.Imperial.Medieval.Ships.Wind;
using Content.Shared.Imperial.Medieval.Skills;
using Content.Shared.Popups;
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs b/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
deleted file mode 100644
index 6345057a131..00000000000
--- a/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Content.Server.Imperial.Medieval.Ships.ShipDrowning;
-
-///
-/// This is used for...
-///
-[RegisterComponent]
-public sealed partial class ShipDrowningComponent : Component
-{
- [DataField("DrownLevel")]
- public int DrownLevel;
-
- [DataField("DrownMaxLevel")]
- public float DrownMaxLevel = 10000000000;
-}
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs b/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs
index 8a09ad07dfd..7afc40dc8f5 100644
--- a/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningSystem.cs
@@ -3,6 +3,7 @@
using Content.Server.Imperial.Medieval.Ships.PlayerDrowning;
using Content.Server.Imperial.Medieval.Ships.Wave;
using Content.Shared.Damage;
+using Content.Shared.Imperial.Medieval.Ships.ShipDrowning;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
@@ -19,7 +20,6 @@ public sealed class ShipDrowningSystem : EntitySystem
[Dependency] private readonly WaveSystem _wave = default!;
private const float DefaultReloadTimeSeconds = 10f;
- public const string ConductorContainer = "Conductor";
private TimeSpan _nextCheckTime;
///
diff --git a/Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs b/Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs
new file mode 100644
index 00000000000..61496dd6eae
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs
@@ -0,0 +1,13 @@
+namespace Content.Server.Imperial.Medieval.Ships.Storm;
+
+///
+/// This handles...
+///
+public sealed class StormSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs b/Content.Shared/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
new file mode 100644
index 00000000000..b2e79164a36
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/ShipDrowning/ShipDrowningComponent.cs
@@ -0,0 +1,21 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Imperial.Medieval.Ships.ShipDrowning;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class ShipDrowningComponent : Component
+{
+ ///
+ /// Уровень затоплености
+ ///
+ [DataField("DrownLevel")]
+ public int DrownLevel;
+ ///
+ /// Максимальный уровень затоплености
+ ///
+ [DataField("DrownMaxLevel")]
+ public float DrownMaxLevel = 10000000000;
+}
From 599b143e4d30f6f779046f3eb0454f611d6e7ee5 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Fri, 6 Mar 2026 20:09:13 +0300
Subject: [PATCH 08/20] =?UTF-8?q?=D0=BB=D0=B5=D0=B9=D1=81=D1=8F=20=D0=B2?=
=?UTF-8?q?=D0=B0=D1=80=D0=B5=D0=B2=D0=BE=20=D1=84=D0=B8=D0=BA=D1=81=D1=8B?=
=?UTF-8?q?=20=D0=B8=20=D1=80=D0=B0=D0=B7=D0=B2=D1=91=D1=80=D1=82=D1=8B?=
=?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B0=D1=80=D1=83=D1=81?=
=?UTF-8?q?=D0=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ну на самом деле это никто не читает а писать фикс я задолбался, а писать развёрнуто мне лень
---
.../Medieval/Ships/Oar/ServerOarSystem.cs | 1 +
.../Medieval/Ships/Sail/SailSystem.cs | 21 ++++++--
.../Medieval/Ships/Sail/SailUseEvent.cs | 4 ++
.../Medieval/Ships/Sail/SharedSailSystem.cs | 52 +++++++++++++++++++
4 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
index 3266e03e801..ee563508411 100644
--- a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
@@ -72,6 +72,7 @@ private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInte
RequireCanInteract = false,
BreakOnDropItem = true,
BreakOnHandChange = true,
+ NeedHand = true,
};
_doAfter.TryStartDoAfter(sdoAfter);
var playerPosition = _transform.GetWorldPosition(playerEntity);
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
index c28c5ee8eb7..a0d72b4778f 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -50,6 +50,7 @@ public sealed class SailSystem : EntitySystem
///
public override void Initialize()
{
+ SubscribeLocalEvent(OnFold);
}
public override void Update(float frameTime)
@@ -153,9 +154,6 @@ private void Push(EntityUid sail, float windForce, Angle torque , bool push = tr
private void RandomiseVind()
{
-
-
-
// ветерок сила
var windForce = _cfg.GetCVar(ShipsCCVars.WindPower);
if (windForce <= 0)
@@ -176,4 +174,21 @@ private void RandomiseVind()
_cfg.SetCVar(ShipsCCVars.WindRotation, windAngle);
}
+
+
+ private void OnFold(EntityUid uid, SailComponent component, SailFoldEvent args)
+ {
+ if (args.Cancelled)
+ return;
+
+ var rot = _transform.GetWorldRotation(uid);
+ var coords = _transform.GetMapCoordinates(uid);
+ Del(uid);
+ if (component.Folded)
+ Spawn("MedievalDecorShipSailReady", coords, rotation: rot);
+ else
+ {
+ Spawn("MedievalDecorShipSailShipup", coords, rotation: rot);
+ }
+ }
}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs b/Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs
index 08edcb90019..783ba2e69e9 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Sail/SailUseEvent.cs
@@ -9,3 +9,7 @@ namespace Content.Shared.Imperial.Medieval.Ships.Sail;
public sealed partial class SailUseEvent : SimpleDoAfterEvent
{
}
+
+public sealed partial class SailFoldEvent : SimpleDoAfterEvent
+{
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs
index bf6d8b23206..de85335a9d6 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Sail/SharedSailSystem.cs
@@ -1,10 +1,15 @@
+using Content.Shared.Database;
using Content.Shared.DoAfter;
+using Content.Shared.Ghost;
using Content.Shared.Imperial.Medieval.Administration.Ships;
+using Content.Shared.Imperial.Medieval.Follower;
using Content.Shared.Imperial.Medieval.Ships.Oar;
using Content.Shared.Imperial.Medieval.Skills;
using Content.Shared.Interaction;
+using Content.Shared.Verbs;
using Robust.Shared.Configuration;
using Robust.Shared.Random;
+using Robust.Shared.Utility;
namespace Content.Shared.Imperial.Medieval.Ships.Sail;
@@ -20,6 +25,7 @@ public sealed class SharedSailSystem : EntitySystem
///
public override void Initialize()
{
+ SubscribeLocalEvent>(OnGetAlternativeVerbs);
SubscribeLocalEvent(OnActivate);
SubscribeLocalEvent(OnInteractUsing);
SubscribeLocalEvent(OnUse);
@@ -60,6 +66,9 @@ private void UseDelay(EntityUid playerEntity, EntityUid targetEntity)
private void OnUse(EntityUid uid, SailComponent component, SailUseEvent args)
{
+ if (args.Cancelled)
+ return;
+
Rotate(uid);
}
@@ -67,4 +76,47 @@ private void Rotate(EntityUid uid)
{
_transform.SetWorldRotation(uid, _cfg.GetCVar(ShipsCCVars.WindRotation)/180);
}
+
+ private void OnGetAlternativeVerbs(GetVerbsEvent ev)
+ {
+ if (ev.User == ev.Target || IsClientSide(ev.Target))
+ return;
+
+ if (!TryComp(ev.Target, out var sail))
+ return;
+ var text = "Сложить";
+ if (sail.Folded)
+ text = "Разложить";
+ var verb = new AlternativeVerb()
+ {
+ Priority = 10,
+ Act = () => TryFold(ev.User, ev.Target),
+ Impact = LogImpact.Low,
+ Text = Loc.GetString(text),
+ };
+ ev.Verbs.Add(verb);
+ }
+
+ private void TryFold(EntityUid playerEntity, EntityUid targetEntity)
+ {
+ var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.15f - _skills.GetSkillLevel(playerEntity, "Intelligence") * 0.15f;
+ var sdoAfter = new DoAfterArgs(EntityManager,
+ playerEntity,
+ time,
+ new SailFoldEvent(),
+ targetEntity,
+ playerEntity)
+ {
+ MovementThreshold = 0.5f,
+ BreakOnMove = true,
+ CancelDuplicate = true,
+ DistanceThreshold = 2,
+ BreakOnDamage = true,
+ RequireCanInteract = false,
+ BreakOnDropItem = true,
+ BreakOnHandChange = true,
+ NeedHand = true,
+ };
+ _doAfter.TryStartDoAfter(sdoAfter);
+ }
}
From b666e10bd6c27305d1ea15cdd62b6d32dd0666f5 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Sat, 7 Mar 2026 17:34:10 +0300
Subject: [PATCH 09/20] =?UTF-8?q?=D1=8F=D0=BA=D0=BE=D1=80=D1=8F=3F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
якоря
---
.../Ships/Anchor/AnchorSwithComponent.cs | 10 ++++++
.../Ships/Anchor/AnchorSwithSystem.cs | 32 +++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithComponent.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs
diff --git a/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithComponent.cs b/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithComponent.cs
new file mode 100644
index 00000000000..8183ba80778
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithComponent.cs
@@ -0,0 +1,10 @@
+namespace Content.Shared.Imperial.Medieval.Ships.Anchor;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class AnchorSwithComponent : Component
+{
+
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs
new file mode 100644
index 00000000000..0c7f59ca2de
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs
@@ -0,0 +1,32 @@
+using Content.Shared.Imperial.Medieval.Ships.Sail;
+using Content.Shared.Interaction;
+
+namespace Content.Shared.Imperial.Medieval.Ships.Anchor;
+
+///
+/// This handles...
+///
+public sealed class AnchorSwithSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnActivate);
+ SubscribeLocalEvent(OnInteractUsing);
+ }
+
+ private void OnInteractUsing(SailComponent component, InteractUsingEvent args)
+ {
+ Use(args.User, args.Target);
+ }
+
+ private void OnActivate(AnchorSwithComponent component, ActivateInWorldEvent args)
+ {
+ Use(args.User, args.Target);
+ }
+
+ private void Use(EntityUid player, EntityUid target)
+ {
+
+ }
+}
From 6bc1330afd05b2e3306b40390cea0ee2504ca6e8 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Sat, 7 Mar 2026 21:05:05 +0300
Subject: [PATCH 10/20] =?UTF-8?q?=D0=AF=D0=BA=D0=BE=D1=80=D1=8F=20=D1=82?=
=?UTF-8?q?=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B3=D0=BE=D1=82=D0=BE=D0=B2?=
=?UTF-8?q?=D1=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Anchor/ServerMedievalAnchorSystem.cs | 47 ++++++++++++++
.../Ships/Anchor/AnchorSwithSystem.cs | 32 ----------
...omponent.cs => MedievalAnchorComponent.cs} | 5 +-
.../Ships/Anchor/MedievalAnchorSystem.cs | 63 +++++++++++++++++++
.../Medieval/Ships/Anchor/UseAnchorEvent.cs | 17 +++++
5 files changed, 130 insertions(+), 34 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs
delete mode 100644 Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs
rename Content.Shared/Imperial/Medieval/Ships/Anchor/{AnchorSwithComponent.cs => MedievalAnchorComponent.cs} (53%)
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Anchor/MedievalAnchorSystem.cs
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Anchor/UseAnchorEvent.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs b/Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs
new file mode 100644
index 00000000000..eb5f1321964
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs
@@ -0,0 +1,47 @@
+using Content.Server.Shuttles.Components;
+using Content.Server.Shuttles.Systems;
+using Content.Shared.Imperial.Medieval.Ships.Anchor;
+
+namespace Content.Server.Imperial.Medieval.Ships.Anchor;
+
+///
+/// This handles...
+///
+public sealed class ServerMedievalAnchorSystem : EntitySystem
+{
+ [Dependency] private readonly ShuttleSystem _shuttleSystem = default!;
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnUseAnchor);
+ }
+
+ private void OnUseAnchor(EntityUid uid, MedievalAnchorComponent component, UseAnchorEvent args)
+ {
+ if (args.Target == null || args.Cancelled)
+ return;
+
+ var target = component.Owner;
+
+ var enabled = component.Enabled;
+
+ ShuttleComponent? shuttleComponent = default;
+
+ var transform = Transform(target);
+ var grid = transform.GridUid;
+ if (!grid.HasValue || !transform.Anchored || !Resolve(grid.Value, ref shuttleComponent))
+ return;
+
+ if (!enabled)
+ {
+ _shuttleSystem.Disable(grid.Value);
+ }
+ else
+ {
+ _shuttleSystem.Enable(grid.Value);
+ }
+
+ shuttleComponent.Enabled = !enabled;
+ component.Enabled = !enabled;
+ }
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs
deleted file mode 100644
index 0c7f59ca2de..00000000000
--- a/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithSystem.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Content.Shared.Imperial.Medieval.Ships.Sail;
-using Content.Shared.Interaction;
-
-namespace Content.Shared.Imperial.Medieval.Ships.Anchor;
-
-///
-/// This handles...
-///
-public sealed class AnchorSwithSystem : EntitySystem
-{
- ///
- public override void Initialize()
- {
- SubscribeLocalEvent(OnActivate);
- SubscribeLocalEvent(OnInteractUsing);
- }
-
- private void OnInteractUsing(SailComponent component, InteractUsingEvent args)
- {
- Use(args.User, args.Target);
- }
-
- private void OnActivate(AnchorSwithComponent component, ActivateInWorldEvent args)
- {
- Use(args.User, args.Target);
- }
-
- private void Use(EntityUid player, EntityUid target)
- {
-
- }
-}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithComponent.cs b/Content.Shared/Imperial/Medieval/Ships/Anchor/MedievalAnchorComponent.cs
similarity index 53%
rename from Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithComponent.cs
rename to Content.Shared/Imperial/Medieval/Ships/Anchor/MedievalAnchorComponent.cs
index 8183ba80778..42503d067c1 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Anchor/AnchorSwithComponent.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Anchor/MedievalAnchorComponent.cs
@@ -4,7 +4,8 @@ namespace Content.Shared.Imperial.Medieval.Ships.Anchor;
/// This is used for...
///
[RegisterComponent]
-public sealed partial class AnchorSwithComponent : Component
+public sealed partial class MedievalAnchorComponent : Component
{
-
+ [DataField("Enabled")]
+ public bool Enabled;
}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Anchor/MedievalAnchorSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Anchor/MedievalAnchorSystem.cs
new file mode 100644
index 00000000000..cec5bc2a831
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Anchor/MedievalAnchorSystem.cs
@@ -0,0 +1,63 @@
+using Content.Shared.Imperial.Medieval.Ships.Sail;
+using Content.Shared.Interaction;
+using Content.Shared.Construction.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.Imperial.Medieval.Skills;
+using Content.Shared.Popups;
+
+
+namespace Content.Shared.Imperial.Medieval.Ships.Anchor;
+
+///
+/// система для поднятия и опускания якоря
+///
+public sealed class MedievalAnchorSystem : EntitySystem
+{
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedSkillsSystem _skills = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnActivate);
+ SubscribeLocalEvent(OnInteractUsing);
+ }
+
+ private void OnInteractUsing(EntityUid uid, MedievalAnchorComponent component, InteractUsingEvent args)
+ {
+ Use(args.User, args.Target);
+ }
+
+ private void OnActivate(EntityUid uid, MedievalAnchorComponent component, ActivateInWorldEvent args)
+ {
+ Use(args.User, args.Target);
+ }
+
+ private void Use(EntityUid playerEntity, EntityUid target)
+ {
+
+
+ var time = 7 -_skills.GetSkillLevel(playerEntity, "Strength") * 0.3f;
+ var sdoAfter = new DoAfterArgs(EntityManager,
+ playerEntity,
+ time,
+ new UseAnchorEvent(),
+ target,
+ target: playerEntity)
+ {
+ MovementThreshold = 0.5f,
+ BreakOnMove = true,
+ CancelDuplicate = true,
+ DistanceThreshold = 2,
+ BreakOnDamage = true,
+ RequireCanInteract = false,
+ BreakOnDropItem = true,
+ BreakOnHandChange = true,
+ NeedHand = true,
+ };
+
+
+ _doAfter.TryStartDoAfter(sdoAfter);
+
+ }
+}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Anchor/UseAnchorEvent.cs b/Content.Shared/Imperial/Medieval/Ships/Anchor/UseAnchorEvent.cs
new file mode 100644
index 00000000000..e6fa7120542
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Anchor/UseAnchorEvent.cs
@@ -0,0 +1,17 @@
+using Content.Shared.DoAfter;
+
+using Robust.Shared.Serialization;
+
+
+namespace Content.Shared.Imperial.Medieval.Ships.Anchor;
+
+///
+/// Ивент для поднятия якоря
+///
+[Serializable, NetSerializable]
+public sealed partial class UseAnchorEvent : SimpleDoAfterEvent
+{
+}
+
+
+
From 4bb2cf9135bdb43413d9c8af56329e41e1fca052 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Sun, 8 Mar 2026 22:07:16 +0300
Subject: [PATCH 11/20] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?=
=?UTF-8?q?=D1=8F=D0=B5=D0=BC=20=D0=BF=D0=BE=D0=BF=D0=B0=D0=BF=20=D0=B2?=
=?UTF-8?q?=D1=91=D1=81=D0=BB=D0=B0=D0=BC=20=D0=B8=20=D1=88=D1=82=D0=BE?=
=?UTF-8?q?=D1=80=D0=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Anchor/ServerMedievalAnchorSystem.cs | 2 +-
.../Medieval/Ships/Oar/ServerOarSystem.cs | 8 ++
.../Medieval/Ships/Sail/SailSystem.cs | 27 +------
.../Medieval/Ships/Wind/ServerWindSystem.cs | 74 ++++++++++++++++++-
.../Administration/Ships/ShipsCCVars.cs | 4 +
.../Medieval/Ships/Sea/SeaComponent.cs | 11 +++
6 files changed, 98 insertions(+), 28 deletions(-)
create mode 100644 Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs b/Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs
index eb5f1321964..9805e4d15ba 100644
--- a/Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Anchor/ServerMedievalAnchorSystem.cs
@@ -43,5 +43,5 @@ private void OnUseAnchor(EntityUid uid, MedievalAnchorComponent component, UseAn
shuttleComponent.Enabled = !enabled;
component.Enabled = !enabled;
- }
+ }
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
index ee563508411..94656be7289 100644
--- a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
@@ -79,6 +79,14 @@ private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInte
var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
var direction = (playerPosition - boatPosition).Normalized();
component.Direction = direction;
+ var pushAngle = direction.ToAngle();
+ var boatAngle = _transform.GetWorldRotation(boat);
+
+ var text = "по курсу";
+ if (Math.Abs(pushAngle-boatAngle)*180 > 90)
+ text = "против курса";
+
+ _popup.PopupClient($"Ты гребёшь {text} лодки", playerEntity);
}
private void OnOarDoAfter(EntityUid uid, OarComponent component, ref OnOarDoAfterEvent args)
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
index a0d72b4778f..fdd79a7dbf7 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -61,9 +61,7 @@ public override void Update(float frameTime)
if (curTime > _nextCheckTime)
{
- _nextCheckTime = curTime + TimeSpan.FromSeconds(_cfg.GetCVar(ShipsCCVars.WindChangeTime));
-
- RandomiseVind();
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(_cfg.GetCVar(ShipsCCVars.WindDelay));
var ships = new List();
var windAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
@@ -152,29 +150,6 @@ private void Push(EntityUid sail, float windForce, Angle torque , bool push = tr
_physics.ApplyLinearImpulse(boat, impulse);
}
- private void RandomiseVind()
- {
- // ветерок сила
- var windForce = _cfg.GetCVar(ShipsCCVars.WindPower);
- if (windForce <= 0)
- windForce += _random.Next(0, 2);
- else if (windForce >= 10)
- windForce -= _random.Next(0, 2);
- else
- windForce += _random.Next(-1, 2);
- _cfg.SetCVar(ShipsCCVars.WindPower, windForce);
-
- // ветерок направление
- var windAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
- windAngle += _random.Next(-1, 2)*5; // ±5 градусов за шаг
- if (Math.Abs(windAngle) > 360)
- windAngle = 0;
- else if (windAngle < 0)
- windAngle += 360;
-
- _cfg.SetCVar(ShipsCCVars.WindRotation, windAngle);
- }
-
private void OnFold(EntityUid uid, SailComponent component, SailFoldEvent args)
{
diff --git a/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
index aad8226fda2..146f5ab8618 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
@@ -1,3 +1,11 @@
+using Content.Server.Shuttles.Components;
+using Content.Shared.Imperial.Medieval.Administration.Ships;
+using Content.Shared.Imperial.Medieval.Ships.Sea;
+using Robust.Shared.Configuration;
+using Robust.Shared.Map;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
namespace Content.Server.Imperial.Medieval.Ships.Wind;
///
@@ -5,9 +13,73 @@ namespace Content.Server.Imperial.Medieval.Ships.Wind;
///
public sealed class ServerWindSystem : EntitySystem
{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedMapSystem _map = default!;
+
+ private TimeSpan _nextCheckTime;
///
public override void Initialize()
{
-
+
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var curTime = _timing.CurTime;
+
+ if (curTime > _nextCheckTime)
+ {
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(_cfg.GetCVar(ShipsCCVars.WindChangeTime));
+ RandomiseVind();
+ }
+ }
+
+
+ private void RandomiseVind()
+ {
+ // ветерок сила
+ var windForce = _cfg.GetCVar(ShipsCCVars.WindPower);
+ var countShips = FindShips();
+
+ if (windForce <= 0+countShips)
+ windForce += _random.Next(0, 2);
+ else if (windForce >= 2 + countShips || countShips >= 10)
+ windForce -= _random.Next(0, 2);
+ else
+ windForce += _random.Next(-1, 2);
+ _cfg.SetCVar(ShipsCCVars.WindPower, windForce);
+
+ // ветерок направление
+ var windAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
+ windAngle += _random.Next(-1, 2)*5; // ±5 градусов за шаг
+ if (Math.Abs(windAngle) > 360)
+ windAngle = 0;
+ else if (windAngle < 0)
+ windAngle += 360;
+
+ _cfg.SetCVar(ShipsCCVars.WindRotation, windAngle);
+ }
+
+ private int FindShips()
+ {
+ var count = 0;
+ foreach (var seaComp in EntityManager.EntityQuery())
+ {
+ if (seaComp.Disabled)
+ continue;
+ var mapUid = seaComp.Owner;
+ MapId mapId = new MapId(mapUid.Id);
+
+ var ships = new HashSet>();
+ _lookup.GetEntitiesOnMap(mapId, ships);
+ count += ships.Count;
+
+ }
+ return count;
}
}
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
index 6ec2ba1036e..2fe8297f7da 100644
--- a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -14,8 +14,12 @@ public sealed class ShipsCCVars : CVars
public static readonly CVarDef WindChangeTime =
CVarDef.Create("ships.windchangetime", 1f, CVar.REPLICATED | CVar.SERVER);
+ public static readonly CVarDef WindDelay =
+ CVarDef.Create("ships.windDelay", 1f, CVar.REPLICATED | CVar.SERVER);
+
public static readonly CVarDef WindPower =
CVarDef.Create("ships.windpower", 1f, CVar.REPLICATED | CVar.SERVER);
+
public static readonly CVarDef WindRotation =
CVarDef.Create("ships.windrotation", 0f, CVar.REPLICATED | CVar.SERVER);
}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs b/Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs
new file mode 100644
index 00000000000..1ceecdf2585
--- /dev/null
+++ b/Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs
@@ -0,0 +1,11 @@
+namespace Content.Shared.Imperial.Medieval.Ships.Sea;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class SeaComponent : Component
+{
+ [DataField("Disabled")]
+ public bool Disabled;
+}
From 54339d389cca3a2374fc50e1a96a4722aefef991 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Wed, 11 Mar 2026 08:10:40 +0300
Subject: [PATCH 12/20] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=D1=8B=20=D0=B4?=
=?UTF-8?q?=D0=BB=D1=8F=20=D0=B2=D0=B5=D1=81=D0=BB=D0=B0,=20=D0=B4=D0=BE?=
=?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B2=D0=BE=D0=BB=D0=BD=D1=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Medieval/Ships/Oar/ServerOarSystem.cs | 104 ++++----
.../Medieval/Ships/Sail/SailSystem.cs | 4 +-
.../Medieval/Ships/Storm/StormSystem.cs | 2 +-
.../Ships/SummonShip/SummonShipSystem.cs | 2 +-
.../Ships/Wave/Spawn/SpawnWindWaveSystem.cs | 89 +++++++
.../Medieval/Ships/Wave/WaveSystem.cs | 37 ++-
.../Medieval/Ships/Wind/ServerWindSystem.cs | 2 +-
.../Administration/Ships/ShipsCCVars.cs | 13 +-
.../Medieval/Ships/Oar/OarComponent.cs | 2 +-
.../Imperial/Medieval/Ships/Oar/OarSystem.cs | 227 +++++++-----------
10 files changed, 279 insertions(+), 203 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
index 94656be7289..ffa1ae86c51 100644
--- a/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Oar/ServerOarSystem.cs
@@ -15,6 +15,8 @@
using Content.Shared.Database;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Imperial.Medieval.Ships.Oar;
+using Content.Shared.Interaction.Components;
+using Content.Shared.Movement.Components;
namespace Content.Server.Imperial.Medieval.Ships.Oar;
@@ -35,62 +37,17 @@ public sealed class OarSystem : EntitySystem
[Dependency] private readonly RDWeightSystem _rdWeight = default!;
public override void Initialize()
{
- SubscribeLocalEvent(OnOarAfterInteract);
SubscribeLocalEvent(OnOarDoAfter);
}
- private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInteractEvent args)
+ private void OnOarDoAfter(EntityUid uid, OarComponent component, ref OnOarDoAfterEvent args)
{
- var playerEntity = args.User;
-
- if (args.Handled || !args.CanReach )
- return;
-
- var boat = _transform.GetParentUid(playerEntity);
-
- if (boat == args.ClickLocation.EntityId)
- return;
-
- var clickEntity = args.ClickLocation.EntityId;
- if (boat == _transform.GetParentUid(clickEntity))
- return;
-
- var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
- var sdoAfter = new DoAfterArgs(EntityManager,
- playerEntity,
- time,
- new OnOarDoAfterEvent(),
- args.Used,
- args.Target,
- args.Used)
+ if (args.Cancelled)
{
- MovementThreshold = 0.5f,
- BreakOnMove = true,
- CancelDuplicate = true,
- DistanceThreshold = 2,
- BreakOnDamage = true,
- RequireCanInteract = false,
- BreakOnDropItem = true,
- BreakOnHandChange = true,
- NeedHand = true,
- };
- _doAfter.TryStartDoAfter(sdoAfter);
- var playerPosition = _transform.GetWorldPosition(playerEntity);
- var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
- var direction = (playerPosition - boatPosition).Normalized();
- component.Direction = direction;
- var pushAngle = direction.ToAngle();
- var boatAngle = _transform.GetWorldRotation(boat);
-
- var text = "по курсу";
- if (Math.Abs(pushAngle-boatAngle)*180 > 90)
- text = "против курса";
-
- _popup.PopupClient($"Ты гребёшь {text} лодки", playerEntity);
- }
+ RemComp(args.User);
+ RemComp(args.User);
+ }
- private void OnOarDoAfter(EntityUid uid, OarComponent component, ref OnOarDoAfterEvent args)
- {
var item = _hands.GetActiveItem(args.User);
if (args.Cancelled || args.Handled || item == null)
return;
@@ -103,12 +60,16 @@ private void OnOarDoAfter(EntityUid uid, OarComponent component, ref OnOarDoAfte
args.Repeat = true;
}
- private void Push(EntityUid item, Vector2 direction, float power, EntityUid player)
+ private void Push(EntityUid item, Angle direction, float power, EntityUid player)
{
- power += power * (10 - _skills.GetSkillLevel(player, "Strength")) * 0.1f;
+ power += power * (-10 + _skills.GetSkillLevel(player, "Strength")) * 0.1f;
var boat = _transform.GetParentUid(player);
+ var boatAngle = _transform.GetWorldRotation(boat);
+
+ var playerAngle = _transform.GetWorldRotation(player);
+
var entities = _lookup.GetEntitiesIntersecting(boat);
if (entities.Count > 1000)
@@ -124,16 +85,47 @@ private void Push(EntityUid item, Vector2 direction, float power, EntityUid play
if (weight == 0)
weight = 10;
- var impulse = direction * (power / weight);
+
+ var directionVec = Vector2.Zero;
+ while (direction > 2)
+ {
+ direction -= 2;
+ }
+
+
+ direction += Angle.FromDegrees(45);
+ // от 0 до 0.5 (1,0)
+ // от 0.5 до 1 (0,1)
+ // от 1 до 1,5 (0,-1)
+ // от 1,5 до 0 (-1,0)
+ if (direction > 1)
+ {
+ if (direction > 1.5)
+ directionVec = new Vector2(-1,0);
+ else
+ {
+ directionVec = new Vector2(0,-1);
+ }
+ }
+ else
+ {
+ if (direction > 0.5)
+ directionVec = new Vector2(0,1);
+ else
+ {
+ directionVec = new Vector2(1,0);
+ }
+ }
+
+ directionVec = playerAngle.RotateVec(directionVec);
+ var impulse = directionVec * (power / weight);
var angleimpulse = (power / weight);
- if (direction.X < 0)
- angleimpulse = -angleimpulse;
if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
{
_physics.WakeBody(boat);
_physics.ApplyLinearImpulse(boat, impulse, body: body);
- _physics.ApplyAngularImpulse(boat, angleimpulse, body: body);
+ // _physics.ApplyAngularImpulse(boat, angleimpulse, body: body);
}
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
index fdd79a7dbf7..3fe822d3974 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -65,7 +65,7 @@ public override void Update(float frameTime)
var ships = new List();
var windAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
- var windForce = _cfg.GetCVar(ShipsCCVars.WindPower);
+ var windForce = _cfg.GetCVar(ShipsCCVars.StormLevel);
foreach (var sailComponent in EntityManager.EntityQuery())
{
if (sailComponent.Folded)
@@ -102,7 +102,7 @@ public override void Update(float frameTime)
}
var diffAngle = sailAngle - windAngle;
- var force = windForce * MathF.Cos(diffAngle/180) * sailComponent.SailSize;
+ var force = windForce * MathF.Cos(diffAngle/180) * sailComponent.SailSize * _cfg.GetCVar(ShipsCCVars.WindPower);
Push(sailEntity, force, boatAngle , push: sailComponent.Push, helm: sailComponent.Helm);
if (!ships.Contains(boat))
diff --git a/Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs b/Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs
index 61496dd6eae..935021994a6 100644
--- a/Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Storm/StormSystem.cs
@@ -8,6 +8,6 @@ public sealed class StormSystem : EntitySystem
///
public override void Initialize()
{
-
+
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs b/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs
index d0ea8da6673..4ffffda320d 100644
--- a/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/SummonShip/SummonShipSystem.cs
@@ -57,7 +57,7 @@ private void Use(EntityUid uid, SummonShipComponent comp)
_adminLog.Add(LogType.Action, LogImpact.High, $"Ошибка Загрузки грида из {path} сущность загрузки {uid}");
return;
}
-
+
EntityManager.QueueDeleteEntity(uid);
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
new file mode 100644
index 00000000000..ffd6043761e
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
@@ -0,0 +1,89 @@
+using System.Numerics;
+using Content.Shared.Imperial.Medieval.Administration.Ships;
+using Content.Shared.Imperial.Medieval.Ships.Sea;
+using Content.Shared.Imperial.Medieval.Ships.ShipDrowning;
+using Content.Shared.Nutrition.Components;
+using Robust.Shared.Configuration;
+using Robust.Shared.Map;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Imperial.Medieval.Ships.Wave.Spawn;
+
+///
+/// Призыв волн раз в какое то время
+///
+public sealed class SpawnWindWaveSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly WaveSystem _wave = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+
+ private TimeSpan _nextCheckTime;
+ ///
+ public override void Initialize()
+ {
+
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var curTime = _timing.CurTime;
+
+ if (curTime > _nextCheckTime)
+ {
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(_cfg.GetCVar(ShipsCCVars.WaveDelay));
+
+ foreach (var seaComponent in EntityManager.EntityQuery())
+ {
+ if (seaComponent.Disabled)
+ continue;
+ var sea = seaComponent.Owner;
+ var seaMapId = _transform.GetMapId(sea);
+ var ships = new HashSet>();
+ _lookup.GetEntitiesOnMap(seaMapId, ships);
+ foreach (var shipcomp in ships)
+ {
+ var ship = shipcomp.Owner;
+
+ var waveCount = _random.Next(1, 5);
+ var waveCoords = new EntityCoordinates(ship, GenerateWave());
+ Vector2 force;
+ for (var i = 0; i < waveCount; i++)
+ {
+ waveCoords = new EntityCoordinates(ship, GenerateWave());
+ force = waveCoords.Position.Normalized()*_cfg.GetCVar(ShipsCCVars.WaveForce)*-1;
+ _wave.SpawnWave(waveCoords,seaMapId, force);
+ }
+
+ }
+
+
+ }
+
+ }
+ }
+ private Vector2 GenerateWave(float radius = 0)
+ {
+ if (radius == 0)
+ radius = _cfg.GetCVar(ShipsCCVars.WaveSpawnRange);
+ // ----- 1. Случайные числа u, v ∈ [0,1) -----
+ var u = _random.NextDouble();
+ var v = _random.NextDouble();
+
+ // ----- 2. Полярные координаты (равномерно по площади) -----
+ var rho = radius * Math.Sqrt(u); // расстояние от центра
+ var phi = 2.0 * Math.PI * v; // угол в радианах
+
+ // ----- 3. Преобразуем в декартовы координаты -----
+ var x = (float)(rho * Math.Cos(phi));
+ var y = (float)(rho * Math.Sin(phi));
+
+ return new Vector2(x, y);
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index 59d098d24ec..5bfc8c3dc47 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -5,6 +5,7 @@
using Content.Shared.Construction.Conditions;
using Content.Shared.Damage;
using Content.Shared.Database;
+using Content.Shared.Imperial.Medieval.Additions;
using Content.Shared.Maps;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
@@ -69,8 +70,6 @@ private void Startup()
if (Stages == null || Stages.Length == 0)
return;
-
- // Используем for вместо foreach для изменения коллекции
for (int i = 0; i < Stages.Length; i++)
{
var stage = Stages[i];
@@ -133,7 +132,7 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
continue;
var stagelast = Stages.Length-1;
- if (tile.TypeId == Stages[stagelast].Item2)
+ if (tile.TypeId == Stages[stagelast].Item2 || tile.IsEmpty)
continue;
var index = 0;
foreach (var stage in Stages)
@@ -151,4 +150,36 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
if (component.DeleteOnCollide)
_entityManager.DeleteEntity(args.OurEntity);
}
+ ///
+ /// призывает грид на куазанных координатах относительно какой то сущности и даёт ей силу
+ /// coords кординаты это сущность от которой считать и вектор смещения
+ /// mapId айди мапы
+ /// force вектор силы который мы прикладываем если надо
+ /// deleteOnCollide при столкновении удаляем
+ /// lifetime = 0 не будет удалять сущность по истечению таймера
+ ///
+ public void SpawnWave(EntityCoordinates coords, MapId mapId, Vector2 force = new Vector2(), bool deleteOnCollide = true, float lifetime = 60)
+ {
+ var grid = _mapManager.CreateGridEntity(mapId);
+ var waveComponent = EnsureComp(grid);
+ waveComponent.DeleteOnCollide = deleteOnCollide;
+ _tileDefinitionManager.TryGetDefinition("FloorWood", out var tileDefinition);// сюда поставить воду
+ if (tileDefinition == null)
+ return;
+ _map.SetTile(grid, new Vector2i(0,0),new Tile(tileDefinition.TileId, 0, 0));// создаёт тайлик воды надо поставить воду вон туда
+ if (HasComp(grid))
+ {
+ _transform.SetCoordinates(grid, coords);
+ _physics.WakeBody(grid);
+ _physics.ApplyLinearImpulse(grid, force);
+ if (lifetime > 0)
+ {
+ var despawnComponent = EnsureComp(grid);
+ despawnComponent.Lifetime = lifetime;
+ despawnComponent.OriginalLifeTime = lifetime;
+ }
+ }
+
+
+ }
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
index 146f5ab8618..9a6c7027153 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wind/ServerWindSystem.cs
@@ -43,7 +43,7 @@ public override void Update(float frameTime)
private void RandomiseVind()
{
// ветерок сила
- var windForce = _cfg.GetCVar(ShipsCCVars.WindPower);
+ var windForce = _cfg.GetCVar(ShipsCCVars.StormLevel);
var countShips = FindShips();
if (windForce <= 0+countShips)
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
index 2fe8297f7da..673f9f2cc00 100644
--- a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -15,12 +15,23 @@ public sealed class ShipsCCVars : CVars
CVarDef.Create("ships.windchangetime", 1f, CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef WindDelay =
- CVarDef.Create("ships.windDelay", 1f, CVar.REPLICATED | CVar.SERVER);
+ CVarDef.Create("ships.winddelay", 1f, CVar.REPLICATED | CVar.SERVER);
+ public static readonly CVarDef WaveDelay =
+ CVarDef.Create("ships.wavedelay", 1f, CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef WindPower =
CVarDef.Create("ships.windpower", 1f, CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef WindRotation =
CVarDef.Create("ships.windrotation", 0f, CVar.REPLICATED | CVar.SERVER);
+
+ public static readonly CVarDef StormLevel =
+ CVarDef.Create("ships.stormlevel", 1f, CVar.REPLICATED | CVar.SERVER);
+
+ public static readonly CVarDef WaveForce =
+ CVarDef.Create("ships.waveforce", 1f, CVar.REPLICATED | CVar.SERVER);
+
+ public static readonly CVarDef WaveSpawnRange =
+ CVarDef.Create("ships.wavespawnrange", 40f, CVar.REPLICATED | CVar.SERVER);
}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs b/Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs
index d54ee8f8d47..7574ed06be6 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Oar/OarComponent.cs
@@ -15,5 +15,5 @@ public sealed partial class OarComponent : Component
public int SpeedModifier = 1;
[DataField]
- public Vector2 Direction;
+ public Angle Direction;
}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
index bbd88a65065..94fb5babda2 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Oar/OarSystem.cs
@@ -1,137 +1,90 @@
-// using System.Numerics;
-// using Content.Shared._RD.Weight.Components;
-// using Content.Shared._RD.Weight.Systems;
-// using Content.Shared.Coordinates;
-// using Content.Shared.DoAfter;
-// using Content.Shared.Imperial.Medieval.Skills;
-// using Content.Shared.Interaction;
-// using Content.Shared.Interaction.Events;
-// using Content.Shared.Popups;
-// using Robust.Shared.Physics;
-// using Robust.Shared.Physics.Components;
-// using Robust.Shared.Physics.Systems;
-//
-//
-// using Content.Shared.Database;
-// using Content.Shared.Hands.EntitySystems;
-//
-//
-// namespace Content.Shared.Imperial.Medieval.Ships.Oar;
-//
-// ///
-// /// По идее это должно быть тут, но млять грёбаный делей
-// ///
-// public sealed class OarSystem : EntitySystem
-// {
-// [Dependency] private readonly SharedPopupSystem _popup = default!;
-// [Dependency] private readonly SharedPhysicsSystem _physics = default!;
-// [Dependency] private readonly SharedTransformSystem _transform = default!;
-// [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
-// [Dependency] private readonly SharedSkillsSystem _skills = default!;
-// [Dependency] private readonly EntityManager _entManager = default!;
-// [Dependency] private readonly EntityLookupSystem _lookup = default!;
-// [Dependency] private readonly SharedHandsSystem _hands = default!;
-// [Dependency] private readonly RDWeightSystem _rdWeight = default!;
-// public override void Initialize()
-// {
-// SubscribeLocalEvent(OnOarAfterInteract);
-// SubscribeLocalEvent(OnOarDoAfter);
-// }
-//
-// private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInteractEvent args)
-// {
-// var playerEntity = args.User;
-//
-// if (args.Handled || !args.CanReach )
-// return;
-//
-//
-// var boat = _transform.GetParentUid(playerEntity);
-//
-//
-// if (boat == args.ClickLocation.EntityId)
-// return;
-//
-// var clickEntity = args.ClickLocation.EntityId;
-// if (boat == _transform.GetParentUid(clickEntity))
-// return;
-//
-// var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
-// var sdoAfter = new DoAfterArgs(EntityManager,
-// playerEntity,
-// time,
-// new OnOarDoAfterEvent(),
-// args.Target,
-// target: args.Used)
-// {
-// MovementThreshold = 0.5f,
-// BreakOnMove = true,
-// CancelDuplicate = true,
-// DistanceThreshold = 2,
-// BreakOnDamage = true,
-// RequireCanInteract = false,
-// BreakOnDropItem = true,
-// BreakOnHandChange = true,
-// };
-//
-//
-// _popup.PopupClient(Loc.GetString($"{playerEntity} {time} {args.Target} {args.Used}"), component.Owner, args.User);
-// _doAfter.TryStartDoAfter(sdoAfter);
-//
-//
-//
-//
-// var playerPosition = _transform.GetWorldPosition(playerEntity);
-// var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
-// var direction = (playerPosition - boatPosition).Normalized();
-// component.Direction = direction;
-// }
-//
-// private void OnOarDoAfter(EntityUid uid, OarComponent component, ref OnOarDoAfterEvent args)
-// {
-// var item = _hands.GetActiveItem(args.User);
-// if (args.Cancelled || args.Handled || item == null)
-// return;
-//
-// if (!TryComp(item, out var comp))
-// return;
-//
-// Push(item.Value, comp.Direction, comp.Power, args.User);
-// args.Handled = true;
-// args.Repeat = true;
-// }
-//
-// private void Push(EntityUid item, Vector2 direction, float power, EntityUid player)
-// {
-// power += power * (10 - _skills.GetSkillLevel(player, "Strength")) * 0.1f;
-//
-// var boat = _transform.GetParentUid(player);
-//
-// var entities = _lookup.GetEntitiesIntersecting(boat);
-//
-// if (entities.Count > 1000)
-// return;
-//
-// var weight = _rdWeight.GetTotal(boat);
-//
-// foreach (var entity in entities)
-// {
-// if (HasComp(entity))
-// weight += _rdWeight.GetTotal(entity);
-// }
-//
-// if (weight == 0)
-// weight = 10;
-// var impulse = direction * (power / weight);
-// var angleimpulse = (power / weight);
-// if (direction.X < 0)
-// angleimpulse = -angleimpulse;
-//
-// if (EntityManager.TryGetComponent(boat, out PhysicsComponent? body))
-// {
-// _physics.WakeBody(boat);
-// _physics.ApplyLinearImpulse(boat, impulse, body: body);
-// _physics.ApplyAngularImpulse(boat, angleimpulse, body: body);
-// }
-// }
-// }
+using System.Numerics;
+using Content.Shared._RD.Weight.Components;
+using Content.Shared._RD.Weight.Systems;
+using Content.Shared.Coordinates;
+using Content.Shared.DoAfter;
+using Content.Shared.Imperial.Medieval.Skills;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Popups;
+using Robust.Shared.Physics;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Physics.Systems;
+
+
+using Content.Shared.Database;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Interaction.Components;
+using Content.Shared.Movement.Components;
+using Robust.Shared.Map;
+
+
+namespace Content.Shared.Imperial.Medieval.Ships.Oar;
+
+///
+/// По идее это должно быть тут, но млять грёбаный делей
+///
+public sealed class OarSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedSkillsSystem _skills = default!;
+ [Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly RDWeightSystem _rdWeight = default!;
+ [Dependency] private readonly SharedMapSystem _map = default!;
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnOarAfterInteract);
+ }
+
+ private void OnOarAfterInteract(EntityUid uid, OarComponent component, AfterInteractEvent args)
+ {
+ var playerEntity = args.User;
+
+ if (args.Handled || !args.CanReach )
+ return;
+
+ var boat = _transform.GetParentUid(playerEntity);
+
+ if (boat == args.ClickLocation.EntityId)
+ return;
+
+ var clickEntity = args.ClickLocation.EntityId;
+ if (boat == _transform.GetParentUid(clickEntity))
+ return;
+
+ var time = 7 -_skills.GetSkillLevel(playerEntity, "Agility") * 0.3f;
+ var sdoAfter = new DoAfterArgs(EntityManager,
+ playerEntity,
+ time,
+ new OnOarDoAfterEvent(),
+ args.Used,
+ args.Target,
+ args.Used)
+ {
+ MovementThreshold = 0.1f,
+ BreakOnMove = true,
+ CancelDuplicate = true,
+ DistanceThreshold = 2,
+ BreakOnDamage = true,
+ RequireCanInteract = false,
+ BreakOnDropItem = true,
+ BreakOnHandChange = true,
+ NeedHand = true,
+ };
+ _doAfter.TryStartDoAfter(sdoAfter);
+ var playerPosition = _transform.GetWorldPosition(playerEntity);
+ var boatPosition = _transform.ToWorldPosition(args.ClickLocation);
+ var direction = (playerPosition - boatPosition).ToAngle();
+ component.Direction = direction;
+
+ _popup.PopupClient($"Ты гребёшь в сторону взгляда", playerEntity);
+ EnsureComp(playerEntity);
+ EnsureComp(playerEntity);
+
+ }
+}
From 5f85677568a215ea4d763c40d69294a3e496f9f9 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Thu, 12 Mar 2026 20:52:25 +0300
Subject: [PATCH 13/20] =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=B2=D0=B5=D1=82=20?=
=?UTF-8?q?=D0=BA=D1=83=D1=87=D0=B0=20=D1=86=D0=B2=D0=B0=D1=80=D0=BE=D0=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Ships/Wave/Spawn/SpawnWindWaveSystem.cs | 24 ++++++++++++-----
.../Medieval/Ships/Wave/WaveSystem.cs | 15 ++++++-----
.../Administration/Ships/ShipsCCVars.cs | 26 ++++++++++++++-----
3 files changed, 45 insertions(+), 20 deletions(-)
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
index ffd6043761e..528cd129de1 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
@@ -51,7 +51,7 @@ public override void Update(float frameTime)
{
var ship = shipcomp.Owner;
- var waveCount = _random.Next(1, 5);
+ var waveCount = _random.Next(0, (int)_cfg.GetCVar(ShipsCCVars.StormLevel));
var waveCoords = new EntityCoordinates(ship, GenerateWave());
Vector2 force;
for (var i = 0; i < waveCount; i++)
@@ -68,22 +68,32 @@ public override void Update(float frameTime)
}
}
- private Vector2 GenerateWave(float radius = 0)
+ private Vector2 GenerateWave(float radius = 0, float targetAngle = 0, float halfAngle = 3.0235f)
{
+ if (halfAngle == 3.0235f) // я прифигею если вы рандомно сможете получить это число
+ halfAngle = _cfg.GetCVar(ShipsCCVars.WaveSpawnAngle)*_cfg.GetCVar(ShipsCCVars.StormLevel);
+
+ halfAngle /= 180;
+
+ if (targetAngle == 0)
+ targetAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
if (radius == 0)
radius = _cfg.GetCVar(ShipsCCVars.WaveSpawnRange);
- // ----- 1. Случайные числа u, v ∈ [0,1) -----
+
var u = _random.NextDouble();
var v = _random.NextDouble();
- // ----- 2. Полярные координаты (равномерно по площади) -----
- var rho = radius * Math.Sqrt(u); // расстояние от центра
- var phi = 2.0 * Math.PI * v; // угол в радианах
+ var rho = radius * Math.Sqrt(u);
+
+ var phiMin = targetAngle - halfAngle;
+ var phiMax = targetAngle + halfAngle;
+ var phi = phiMin + (phiMax - phiMin) * v;
+
- // ----- 3. Преобразуем в декартовы координаты -----
var x = (float)(rho * Math.Cos(phi));
var y = (float)(rho * Math.Sin(phi));
return new Vector2(x, y);
}
+
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index 5bfc8c3dc47..b0e79dca496 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -6,6 +6,7 @@
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.Imperial.Medieval.Additions;
+using Content.Shared.Imperial.Medieval.Administration.Ships;
using Content.Shared.Maps;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
@@ -15,6 +16,7 @@
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
+using Robust.Shared.Configuration;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
@@ -45,6 +47,7 @@ public sealed class WaveSystem : EntitySystem
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly IAdminLogManager _adminlogs = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
private readonly Random _random = new();
@@ -55,7 +58,6 @@ public sealed class WaveSystem : EntitySystem
("Plating", (ushort)3),
("FloorWhite", (ushort)4)
};
- private const float RadiusTiles = 3f;
private bool _initialized;
public override void Initialize()
@@ -101,13 +103,15 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
var centerTilePos = _map.MapToGrid(grid, collisionPos);
- var antiradius = (int)RadiusTiles*-1;
+ var radiusTiles = _cfg.GetCVar(ShipsCCVars.WaveRadiusTiles) + _cfg.GetCVar(ShipsCCVars.StormLevel);
+
+ var antiradius = (int)radiusTiles*-1;
var nearbyTiles = new List();
- for (int dx = antiradius; dx <= RadiusTiles; dx++)
+ for (int dx = antiradius; dx <= radiusTiles; dx++)
{
- for (int dy = antiradius; dy <= RadiusTiles; dy++)
+ for (int dy = antiradius; dy <= radiusTiles; dy++)
{
var tilePos = centerTilePos + new EntityCoordinates(gridEntity, new Vector2(dx, dy)) ;
var tile = _map.GetTileRef(grid, tilePos);
@@ -116,7 +120,7 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
continue;
var distance = Vector2.Distance(centerTilePos.Position, tilePos.Position);
- if (distance <= RadiusTiles)
+ if (distance <= radiusTiles)
nearbyTiles.Add(((int)tilePos.X, (int)tilePos.Y));
}
}
@@ -124,7 +128,6 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
_random.Shuffle(nearbyTiles);
int tilesToReplace = Math.Min(_random.Next(0,4), nearbyTiles.Count);
- _popup.PopupEntity(Loc.GetString($" {tilesToReplace}"), uid);
for (int i = 0; i < tilesToReplace; i++)
{
var tilePos = nearbyTiles[i];
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
index 673f9f2cc00..a7712e89a0e 100644
--- a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -8,30 +8,42 @@ namespace Content.Shared.Imperial.Medieval.Administration.Ships;
[CVarDefs]
public sealed class ShipsCCVars : CVars
{
+ // максимальная скорость
public static readonly CVarDef ShipsMaxSpeed =
CVarDef.Create("ships.maxspeed", 20f, CVar.REPLICATED | CVar.SERVER);
-
+ // как часто меняется ветер
public static readonly CVarDef WindChangeTime =
CVarDef.Create("ships.windchangetime", 1f, CVar.REPLICATED | CVar.SERVER);
-
+ // как часто ветер дует
public static readonly CVarDef WindDelay =
CVarDef.Create("ships.winddelay", 1f, CVar.REPLICATED | CVar.SERVER);
+ // как часто появляются волны
public static readonly CVarDef WaveDelay =
CVarDef.Create("ships.wavedelay", 1f, CVar.REPLICATED | CVar.SERVER);
-
+// сила с которой ветер толкает
public static readonly CVarDef WindPower =
CVarDef.Create("ships.windpower", 1f, CVar.REPLICATED | CVar.SERVER);
-
+// угол поворота ветра
public static readonly CVarDef WindRotation =
CVarDef.Create("ships.windrotation", 0f, CVar.REPLICATED | CVar.SERVER);
-
+// уровень шторма
public static readonly CVarDef StormLevel =
CVarDef.Create("ships.stormlevel", 1f, CVar.REPLICATED | CVar.SERVER);
-
+// скорость с которой волна спавнится
public static readonly CVarDef WaveForce =
CVarDef.Create("ships.waveforce", 1f, CVar.REPLICATED | CVar.SERVER);
-
+// радиус спавна волн
public static readonly CVarDef WaveSpawnRange =
CVarDef.Create("ships.wavespawnrange", 40f, CVar.REPLICATED | CVar.SERVER);
+// угол разброса волн
+ public static readonly CVarDef WaveSpawnAngle =
+ CVarDef.Create("ships.wavespawnangle", 10f, CVar.REPLICATED | CVar.SERVER);
+ // в каком радиусе ломает волна
+ public static readonly CVarDef WaveRadiusTiles =
+ CVarDef.Create("ships.waveradiustiles", 3f, CVar.REPLICATED | CVar.SERVER);
+// какое максимальное количество тайлов может сломать волна
+ public static readonly CVarDef WaveMaxBreakCount =
+ CVarDef.Create("ships.wavemaxbreakcount", 3f, CVar.REPLICATED | CVar.SERVER);
+
}
From a1781fba31918fbc2394125e12cc30f3cc2ec920 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Thu, 12 Mar 2026 22:00:25 +0300
Subject: [PATCH 14/20] =?UTF-8?q?=D0=91=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20?=
=?UTF-8?q?=D1=86=D0=B2=D0=B0=D1=80=D0=BE=D0=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ShipTeleporting/ShipTeleportSystem.cs | 13 +++++++++
.../Medieval/Ships/Wave/WaveSystem.cs | 28 +++++++++++++++++--
.../Administration/Ships/ShipsCCVars.cs | 21 ++++++++------
3 files changed, 50 insertions(+), 12 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
new file mode 100644
index 00000000000..f09fa773645
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
@@ -0,0 +1,13 @@
+namespace Content.Server.Imperial.Medieval.Ships.ShipTeleporting;
+
+///
+/// This handles...
+///
+public sealed class ShipTeleportSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index b0e79dca496..3cd9ab76f81 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -11,6 +11,7 @@
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
using Content.Shared.Popups;
+using Content.Shared.Tag;
using Content.Shared.Tiles;
using Content.Shared.Trigger.Components;
using Robust.Server.GameObjects;
@@ -48,6 +49,7 @@ public sealed class WaveSystem : EntitySystem
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly IAdminLogManager _adminlogs = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly TagSystem _tags = default!;
private readonly Random _random = new();
@@ -91,6 +93,8 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
return;
if (component.HitList.Contains(args.OtherEntity))
return;
+ if (_cfg.GetCVar(ShipsCCVars.WaveMinToBreakLevel) > _cfg.GetCVar(ShipsCCVars.StormLevel))
+ _entityManager.DeleteEntity(args.OurEntity);
EnsureComp(args.OurEntity);
var collisionPos = _transform.GetMapCoordinates(args.OurEntity);
var gridEntity = args.OtherEntity;
@@ -109,6 +113,7 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
var nearbyTiles = new List();
+
for (int dx = antiradius; dx <= radiusTiles; dx++)
{
for (int dy = antiradius; dy <= radiusTiles; dy++)
@@ -118,6 +123,19 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
if (tile.Tile.IsEmpty)
continue;
+ var wallcheck = new HashSet();
+ _lookup.GetEntitiesInTile(tile, wallcheck);
+ var stop = false;
+ foreach (var wall in wallcheck)
+ {
+ if (_tags.HasTag(wall, "Wall"))
+ {
+ stop = true;
+ }
+
+ }
+ if (stop)
+ continue;
var distance = Vector2.Distance(centerTilePos.Position, tilePos.Position);
if (distance <= radiusTiles)
@@ -127,7 +145,7 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
_random.Shuffle(nearbyTiles);
- int tilesToReplace = Math.Min(_random.Next(0,4), nearbyTiles.Count);
+ int tilesToReplace = Math.Min(_random.Next(0,_cfg.GetCVar(ShipsCCVars.WaveMaxBreakCount)), nearbyTiles.Count);
for (int i = 0; i < tilesToReplace; i++)
{
var tilePos = nearbyTiles[i];
@@ -163,7 +181,13 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
///
public void SpawnWave(EntityCoordinates coords, MapId mapId, Vector2 force = new Vector2(), bool deleteOnCollide = true, float lifetime = 60)
{
+ if (!_map.TryGetMap(mapId, out var mapEntity))
+ {
+ return;
+ }
+
var grid = _mapManager.CreateGridEntity(mapId);
+ _transform.AttachToGridOrMap(grid);
var waveComponent = EnsureComp(grid);
waveComponent.DeleteOnCollide = deleteOnCollide;
_tileDefinitionManager.TryGetDefinition("FloorWood", out var tileDefinition);// сюда поставить воду
@@ -182,7 +206,5 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
despawnComponent.OriginalLifeTime = lifetime;
}
}
-
-
}
}
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
index a7712e89a0e..06e3b9f326e 100644
--- a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -20,30 +20,33 @@ public sealed class ShipsCCVars : CVars
// как часто появляются волны
public static readonly CVarDef WaveDelay =
CVarDef.Create("ships.wavedelay", 1f, CVar.REPLICATED | CVar.SERVER);
-// сила с которой ветер толкает
+ // сила с которой ветер толкает
public static readonly CVarDef WindPower =
CVarDef.Create("ships.windpower", 1f, CVar.REPLICATED | CVar.SERVER);
-// угол поворота ветра
+ // угол поворота ветра
public static readonly CVarDef WindRotation =
CVarDef.Create("ships.windrotation", 0f, CVar.REPLICATED | CVar.SERVER);
-// уровень шторма
+ // уровень шторма
public static readonly CVarDef StormLevel =
CVarDef.Create("ships.stormlevel", 1f, CVar.REPLICATED | CVar.SERVER);
-// скорость с которой волна спавнится
+ // скорость с которой волна спавнится
public static readonly CVarDef WaveForce =
CVarDef.Create("ships.waveforce", 1f, CVar.REPLICATED | CVar.SERVER);
-// радиус спавна волн
+ // радиус спавна волн
public static readonly CVarDef WaveSpawnRange =
CVarDef.Create("ships.wavespawnrange", 40f, CVar.REPLICATED | CVar.SERVER);
-// угол разброса волн
+ // угол разброса волн
public static readonly CVarDef WaveSpawnAngle =
CVarDef.Create("ships.wavespawnangle", 10f, CVar.REPLICATED | CVar.SERVER);
// в каком радиусе ломает волна
public static readonly CVarDef WaveRadiusTiles =
CVarDef.Create("ships.waveradiustiles", 3f, CVar.REPLICATED | CVar.SERVER);
-// какое максимальное количество тайлов может сломать волна
- public static readonly CVarDef WaveMaxBreakCount =
- CVarDef.Create("ships.wavemaxbreakcount", 3f, CVar.REPLICATED | CVar.SERVER);
+ // какое максимальное количество тайлов может сломать волна
+ public static readonly CVarDef WaveMaxBreakCount =
+ CVarDef.Create("ships.wavemaxbreakcount", 3, CVar.REPLICATED | CVar.SERVER);
+ // Минимальный уровень для поломки лодки (Шторма если кто не понял)
+ public static readonly CVarDef WaveMinToBreakLevel =
+ CVarDef.Create("ships.wavemintobreaklevel", 2, CVar.REPLICATED | CVar.SERVER);
}
From 696da023fff109d120464161543eaef09e72d4e2 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Fri, 13 Mar 2026 08:29:09 +0300
Subject: [PATCH 15/20] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=D0=B8=D0=BC=20?=
=?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BD=D1=8B,=20=D0=B4=D0=BE=D0=B1=D0=B0?=
=?UTF-8?q?=D0=B2=D0=BB=D1=8F=D0=B5=D0=BC=20=D0=BF=D0=B5=D1=80=D0=B2=D0=B8?=
=?UTF-8?q?=D1=87=D0=BD=D1=8B=D0=B9=20=D1=82=D0=B5=D0=BB=D0=B5=D0=BF=D0=BE?=
=?UTF-8?q?=D1=80=D1=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Sea/Generation/SeasGenerationSystem.cs | 13 +++++
.../ShipTeleporting/ShipTeleportSystem.cs | 53 ++++++++++++++++++-
.../Ships/Wave/Spawn/SpawnWindWaveSystem.cs | 2 +-
.../Medieval/Ships/Wave/WaveSystem.cs | 6 +--
4 files changed, 68 insertions(+), 6 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
new file mode 100644
index 00000000000..7fa7201d13c
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
@@ -0,0 +1,13 @@
+namespace Content.Server.Imperial.Medieval.Ships.Sea.Generation;
+
+///
+/// This handles...
+///
+public sealed class SeasGenerationSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+
+ }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
index f09fa773645..1010bbd6d73 100644
--- a/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
@@ -1,3 +1,11 @@
+using Content.Server.Imperial.Medieval.Ships.Wave;
+using Content.Shared.Imperial.Medieval.Administration.Ships;
+using Content.Shared.Imperial.Medieval.Ships.Sea;
+using Robust.Shared.Configuration;
+using Robust.Shared.Map;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
namespace Content.Server.Imperial.Medieval.Ships.ShipTeleporting;
///
@@ -5,9 +13,52 @@ namespace Content.Server.Imperial.Medieval.Ships.ShipTeleporting;
///
public sealed class ShipTeleportSystem : EntitySystem
{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly WaveSystem _wave = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+
+ private TimeSpan _nextCheckTime;
///
public override void Initialize()
{
-
+
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var curTime = _timing.CurTime;
+
+ if (curTime > _nextCheckTime)
+ {
+ _nextCheckTime = curTime + TimeSpan.FromSeconds(_cfg.GetCVar(ShipsCCVars.WaveDelay));
+
+ foreach (var seaComponent in EntityManager.EntityQuery())
+ {
+ var ship = seaComponent.Owner;
+
+ var coords = _transform.GetMapCoordinates(ship);
+ if (Math.Abs(coords.X) > 250 || Math.Abs(coords.Y) > 250)
+ {
+ TeleportShip(ship, coords);
+ }
+
+ }
+ }
+ }
+
+ private void TeleportShip(EntityUid ship, MapCoordinates coords)
+ {
+ var newcoords = coords.Position;
+ if (Math.Abs(newcoords.X) > 250)
+ newcoords.X *= -1;
+ if (Math.Abs(newcoords.Y) > 250)
+ newcoords.Y *= -1;
+ var nmapcoords = new MapCoordinates(newcoords, coords.MapId);
+ _transform.SetMapCoordinates(ship, nmapcoords);
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
index 528cd129de1..a256a6ee574 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/Spawn/SpawnWindWaveSystem.cs
@@ -93,7 +93,7 @@ private Vector2 GenerateWave(float radius = 0, float targetAngle = 0, float half
var x = (float)(rho * Math.Cos(phi));
var y = (float)(rho * Math.Sin(phi));
- return new Vector2(x, y);
+ return new Vector2(x*100, y);
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
index 3cd9ab76f81..99df4fa16e8 100644
--- a/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Wave/WaveSystem.cs
@@ -182,18 +182,16 @@ private void OnCollide(EntityUid uid, WaveComponent component, ref StartCollideE
public void SpawnWave(EntityCoordinates coords, MapId mapId, Vector2 force = new Vector2(), bool deleteOnCollide = true, float lifetime = 60)
{
if (!_map.TryGetMap(mapId, out var mapEntity))
- {
return;
- }
var grid = _mapManager.CreateGridEntity(mapId);
- _transform.AttachToGridOrMap(grid);
+ _transform.SetParent(grid, mapEntity.Value);
var waveComponent = EnsureComp(grid);
waveComponent.DeleteOnCollide = deleteOnCollide;
_tileDefinitionManager.TryGetDefinition("FloorWood", out var tileDefinition);// сюда поставить воду
if (tileDefinition == null)
return;
- _map.SetTile(grid, new Vector2i(0,0),new Tile(tileDefinition.TileId, 0, 0));// создаёт тайлик воды надо поставить воду вон туда
+ _map.SetTile(grid, new Vector2i(0,0), new Tile(tileDefinition.TileId, 0, 0));// создаёт тайлик воды надо поставить воду вон туда
if (HasComp(grid))
{
_transform.SetCoordinates(grid, coords);
From cbd9262404760e6cab8a0ed096995f39ca9c7ce9 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Sat, 14 Mar 2026 10:38:05 +0300
Subject: [PATCH 16/20] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B2=D0=B8=D1=87?=
=?UTF-8?q?=D0=BD=D0=B0=D1=8F=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86?=
=?UTF-8?q?=D0=B8=D1=8F=20=D0=BC=D0=BE=D1=80=D0=B5=D0=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ура я починил материнку
---
.../Medieval/Barrier/MagicBarrierComponent.cs | 17 ++
.../Medieval/Ships/Sail/SailSystem.cs | 3 +-
.../Ships/Sea/Init/NotSeaComponent.cs | 14 ++
.../Ships/Sea/Init/SeaMatrixInitSystem.cs | 158 ++++++++++++++++++
.../Administration/Ships/ShipsCCVars.cs | 3 +
5 files changed, 194 insertions(+), 1 deletion(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Sea/Init/NotSeaComponent.cs
create mode 100644 Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
diff --git a/Content.Server/Imperial/Medieval/Barrier/MagicBarrierComponent.cs b/Content.Server/Imperial/Medieval/Barrier/MagicBarrierComponent.cs
index 225749c267e..ad4d8d58e44 100644
--- a/Content.Server/Imperial/Medieval/Barrier/MagicBarrierComponent.cs
+++ b/Content.Server/Imperial/Medieval/Barrier/MagicBarrierComponent.cs
@@ -1,3 +1,6 @@
+using System.Numerics;
+using Content.Server.Imperial.Medieval.Ships.Sea.Init;
+using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Prototypes;
@@ -21,15 +24,19 @@ public sealed partial class MagicBarrierComponent : Component
[DataField]
public float MaxStability = 60f;
+
[DataField]
public float Lose = 0.7f;
+
[DataField]
public float Rate = 1.5f;
+
[DataField]
public int Cycle = 0;
[DataField, ViewVariables(VVAccess.ReadOnly)]
public string EffectSoundOnScrollAdd = "/Audio/Imperial/Medieval/scroll_use.ogg";
+
[DataField, ViewVariables(VVAccess.ReadOnly)]
public string EffectSoundOnFinish = "/Audio/Imperial/Medieval/magic_craft.ogg";
@@ -49,5 +56,15 @@ public sealed partial class MagicBarrierComponent : Component
[DataField]
public Dictionary ReviveCount = new();
+
+ // Приветик, делаем генерацию морей
+ [DataField]
+ public bool SeaInitalazed = false;
+
+
+ [DataField]
+ public SeaMatrix? SeaMatrix = null;
}
}
+
+
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
index 3fe822d3974..3fc47b04403 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -62,7 +62,8 @@ public override void Update(float frameTime)
if (curTime > _nextCheckTime)
{
_nextCheckTime = curTime + TimeSpan.FromSeconds(_cfg.GetCVar(ShipsCCVars.WindDelay));
-
+ if (!_cfg.GetCVar(ShipsCCVars.WindEnabled))
+ return;
var ships = new List();
var windAngle = _cfg.GetCVar(ShipsCCVars.WindRotation);
var windForce = _cfg.GetCVar(ShipsCCVars.StormLevel);
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Init/NotSeaComponent.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Init/NotSeaComponent.cs
new file mode 100644
index 00000000000..dc45733eb13
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Init/NotSeaComponent.cs
@@ -0,0 +1,14 @@
+namespace Content.Server.Imperial.Medieval.Ships.Sea.Init;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class NotSeaComponent : Component
+{
+ [DataField("NotSeaPosX")]
+ public int NotSeaPosX;
+
+ [DataField("NotSeaPosY")]
+ public int NotSeaPosY;
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
new file mode 100644
index 00000000000..daa7a97f727
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
@@ -0,0 +1,158 @@
+using Content.Server.MagicBarrier.Components;
+using Robust.Server.GameObjects;
+using Robust.Shared.Map;
+
+namespace Content.Server.Imperial.Medieval.Ships.Sea.Init;
+
+///
+/// по идее должно работать с матрицой моря
+/// грёбаные костыли, я только примерно понимаю что делаю но вроде как всё нормально(нет я не пишу нейронкой, просто не особо понимаю, райдер помогает исправлять слишком грубые ошибки)
+///
+public sealed class SeaMatrixInitSystem : EntitySystem
+{
+ [Dependency] private readonly MapSystem _map = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly EntityManager _entManager = default!;
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnInit);
+ }
+
+ private void OnInit(EntityUid uid, MagicBarrierComponent component, ComponentInit args)
+ {
+ if (component.SeaMatrix == null)
+ component.SeaMatrix = new SeaMatrix(new List<(int x, int y)>
+ {
+ (2, 2), (2, 3), (2, 4),
+ (3, 2), (3, 3), (3, 4),
+ (4, 2), (4, 3), (4, 4),
+ });
+
+ if (component.SeaInitalazed)
+ return;
+
+ var seamat = component.SeaMatrix;
+
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ if (!seamat.NeedsGeneration(x, y))
+ {
+ if (seamat.GetCell(x, y).SeaId == new MapId(1))
+ {
+ seamat.SetSeaId(x, y, TryFoundMap(x,y));
+ }
+ }
+ var mapUid = _map.CreateMap();
+ var mapId = _transform.GetMapId(mapUid);
+ seamat.SetSeaId(x,y,mapId);
+ seamat.SetGenerated(x,y,true);
+
+ }
+ }
+
+
+ }
+
+ ///
+ /// ищем мапу либо -1 пишем
+ ///
+ public MapId TryFoundMap(int x, int y)
+ {
+ if (_entManager == null)
+ throw new InvalidOperationException("EntityManager not initialized!");
+ foreach (var notSeaComponent in _entManager.EntityQuery())
+ {
+ if (notSeaComponent.NotSeaPosX != x || notSeaComponent.NotSeaPosY != y)
+ continue;
+
+ return _transform.GetMapId(notSeaComponent.Owner);
+ }
+ return new MapId(-1);
+ }
+
+
+
+
+
+
+}
+public sealed class SeaMatrix
+{
+
+ private readonly SeaCell[,] _matrix = new SeaCell[5, 5]; // 5x5 матрица
+
+
+ public SeaMatrix(IEnumerable<(int x, int y)>? nonGeneratableCoordinates = null)
+ {
+
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ _matrix[x, y] = new SeaCell
+ {
+ SeaId = new MapId(-1),
+ NeedGenerate = true
+ };
+ }
+ }
+
+
+ if (nonGeneratableCoordinates != null)
+ {
+ foreach (var (x, y) in nonGeneratableCoordinates)
+ {
+ if (x >= 0 && x < 5 && y >= 0 && y < 5)
+ {
+ _matrix[x, y].NeedGenerate = false;
+ }
+ }
+ }
+ }
+
+
+ ///
+ /// Получение ячейки по координатам
+ ///
+ public SeaCell GetCell(int x, int y)
+ {
+ if (x < 0 || x >= 5 || y < 0 || y >= 5)
+ throw new ArgumentOutOfRangeException("Coordinates out of 5x5 range!");
+
+ return _matrix[x, y];
+ }
+ ///
+ /// Установка ID моря
+ ///
+ public void SetSeaId(int x, int y, MapId seaId)
+ {
+ if (x < 0 || x >= 5 || y < 0 || y >= 5)
+ throw new ArgumentOutOfRangeException("Coordinates out of 5x5 range!");
+
+ _matrix[x, y].SeaId = seaId;
+ _matrix[x, y].NeedGenerate = false; // Сбрасываем флаг после назначения ID
+ }
+
+ ///
+ /// Проверка, нужно ли генерировать море в ячейке
+ ///
+ public bool NeedsGeneration(int x, int y)
+ {
+ return GetCell(x, y).NeedGenerate;
+ }
+ ///
+ /// Ставим значение ячейке
+ ///
+ public void SetGenerated(int x, int y, bool generated)
+ {
+ _matrix[x, y].NeedGenerate = generated;
+ }
+}
+public struct SeaCell
+{
+ public MapId SeaId; // Уникальный ID моря
+ public bool NeedGenerate; // Флаг, что море нужно сгенерировать
+}
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
index 06e3b9f326e..68016f2c6c6 100644
--- a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -20,6 +20,9 @@ public sealed class ShipsCCVars : CVars
// как часто появляются волны
public static readonly CVarDef WaveDelay =
CVarDef.Create("ships.wavedelay", 1f, CVar.REPLICATED | CVar.SERVER);
+ // Минимальный уровень для поломки лодки (Шторма если кто не понял)
+ public static readonly CVarDef WindEnabled =
+ CVarDef.Create("ships.waveenabled", true, CVar.REPLICATED | CVar.SERVER);
// сила с которой ветер толкает
public static readonly CVarDef WindPower =
CVarDef.Create("ships.windpower", 1f, CVar.REPLICATED | CVar.SERVER);
From 3a72432560574bdb37164801a587617d7cd512b5 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Tue, 17 Mar 2026 18:45:21 +0300
Subject: [PATCH 17/20] =?UTF-8?q?=D0=BA=D0=BE=D1=80=D0=B0=D0=B1=D0=BB?=
=?UTF-8?q?=D0=B8=D0=BA=D0=B8=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?=
=?UTF-8?q?=D0=BF=D0=BB=D0=B0=D0=B2=D0=B0=D1=8E=D1=82=20=D0=BC=D0=B5=D0=B6?=
=?UTF-8?q?=D0=B4=D1=83=20=D0=BA=D0=B0=D1=80=D1=82=D0=B0=D0=BC=D0=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Medieval/Ships/Helm/HelmSystem.cs | 1 -
.../Medieval/Ships/Sail/SailSystem.cs | 6 +-
.../Ships/Sea/Init/SeaMatrixInitSystem.cs | 23 +++++-
.../ShipTeleporting/ShipTeleportSystem.cs | 71 ++++++++++++++++---
.../Medieval/Ships/Sea/SeaComponent.cs | 2 +-
5 files changed, 88 insertions(+), 15 deletions(-)
diff --git a/Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs b/Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs
index f248a39cf0b..44516d3203a 100644
--- a/Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Helm/HelmSystem.cs
@@ -70,7 +70,6 @@ public float CheckForce(EntityUid boat, EntityUid helm)
var helmsin = MathF.Sin(boatAngle);
var helmVector = _physics.GetMapLinearVelocity(boat);
var helmForce = Math.Abs(helmVector.X) + Math.Abs(helmVector.Y);
- _adminLog.Add(LogType.Action, LogImpact.Extreme, $"хельма {helmForce}");
return helmForce;
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
index 3fc47b04403..4d5c1c227e8 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sail/SailSystem.cs
@@ -11,6 +11,7 @@
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Imperial.Medieval.Administration.Ships;
using Content.Shared.Imperial.Medieval.Ships.Sail;
+using Content.Shared.Imperial.Medieval.Ships.Sea;
using Content.Shared.Imperial.Medieval.Ships.ShipDrowning;
using Content.Shared.Imperial.Medieval.Ships.Wind;
using Content.Shared.Imperial.Medieval.Skills;
@@ -103,7 +104,10 @@ public override void Update(float frameTime)
}
var diffAngle = sailAngle - windAngle;
- var force = windForce * MathF.Cos(diffAngle/180) * sailComponent.SailSize * _cfg.GetCVar(ShipsCCVars.WindPower);
+ var wind = _cfg.GetCVar(ShipsCCVars.WindPower);
+ if (!HasComp < SeaComponent > (_transform.GetMap(boat)))
+ wind = 1;
+ var force = windForce * MathF.Cos(diffAngle/180) * sailComponent.SailSize * wind;
Push(sailEntity, force, boatAngle , push: sailComponent.Push, helm: sailComponent.Helm);
if (!ships.Contains(boat))
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
index daa7a97f727..a0721dfbaca 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
@@ -1,4 +1,5 @@
using Content.Server.MagicBarrier.Components;
+using Content.Shared.Imperial.Medieval.Ships.Sea;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
@@ -13,6 +14,7 @@ public sealed class SeaMatrixInitSystem : EntitySystem
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly MetaDataSystem _metaData = default!;
///
public override void Initialize()
{
@@ -46,7 +48,9 @@ private void OnInit(EntityUid uid, MagicBarrierComponent component, ComponentIni
}
}
var mapUid = _map.CreateMap();
+ _metaData.SetEntityName(mapUid, $"Море {x} {y}");
var mapId = _transform.GetMapId(mapUid);
+ AddComp(mapUid);
seamat.SetSeaId(x,y,mapId);
seamat.SetGenerated(x,y,true);
@@ -113,7 +117,6 @@ public SeaMatrix(IEnumerable<(int x, int y)>? nonGeneratableCoordinates = null)
}
}
-
///
/// Получение ячейки по координатам
///
@@ -150,6 +153,24 @@ public void SetGenerated(int x, int y, bool generated)
{
_matrix[x, y].NeedGenerate = generated;
}
+
+ ///
+ /// Поиск ячейки по айди
+ ///
+ public (int, int)? FoundSell(MapId seaId, SeaMatrix seaMatrix)
+ {
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ if (_matrix[x, y].SeaId == seaId)
+ {
+ return (x, y);
+ }
+ }
+ }
+ return null;
+ }
}
public struct SeaCell
{
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
index 1010bbd6d73..d71ee711acf 100644
--- a/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
@@ -1,8 +1,12 @@
+using Content.Server.Administration.Logs;
using Content.Server.Imperial.Medieval.Ships.Wave;
+using Content.Server.MagicBarrier.Components;
+using Content.Shared.Database;
using Content.Shared.Imperial.Medieval.Administration.Ships;
using Content.Shared.Imperial.Medieval.Ships.Sea;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
using Robust.Shared.Random;
using Robust.Shared.Timing;
@@ -19,6 +23,7 @@ public sealed class ShipTeleportSystem : EntitySystem
[Dependency] private readonly WaveSystem _wave = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly IAdminLogManager _adminLog = default!;
private TimeSpan _nextCheckTime;
///
@@ -39,14 +44,22 @@ public override void Update(float frameTime)
foreach (var seaComponent in EntityManager.EntityQuery())
{
- var ship = seaComponent.Owner;
- var coords = _transform.GetMapCoordinates(ship);
- if (Math.Abs(coords.X) > 250 || Math.Abs(coords.Y) > 250)
+ var sea = seaComponent.Owner;
+
+ var entities = new HashSet>();
+ _lookup.GetEntitiesOnMap(_transform.GetMapId(sea), entities);
+ foreach (var shipComp in entities)
{
- TeleportShip(ship, coords);
- }
+ var ship = shipComp.Owner;
+
+ var coords = _transform.GetMapCoordinates(ship);
+ if (Math.Abs(coords.X) > 250 || Math.Abs(coords.Y) > 250)
+ {
+ TeleportShip(ship, coords);
+ }
+ }
}
}
}
@@ -54,11 +67,47 @@ public override void Update(float frameTime)
private void TeleportShip(EntityUid ship, MapCoordinates coords)
{
var newcoords = coords.Position;
- if (Math.Abs(newcoords.X) > 250)
- newcoords.X *= -1;
- if (Math.Abs(newcoords.Y) > 250)
- newcoords.Y *= -1;
- var nmapcoords = new MapCoordinates(newcoords, coords.MapId);
- _transform.SetMapCoordinates(ship, nmapcoords);
+ foreach (var magicBarrier in EntityManager.EntityQuery())
+ {
+ var seematrix = magicBarrier.SeaMatrix;
+ if ( seematrix is null)
+ continue;
+ var seamap = seematrix.FoundSell(coords.MapId, seematrix);
+ if (seamap is null)
+ continue;
+
+ var (x, y) = seamap.Value;
+
+ if (Math.Abs(newcoords.X) > 250)
+ {
+ if (newcoords.X > 0)
+ x += 1;
+ else
+ {
+ x -= 1;
+ }
+ newcoords.X *= -1;
+ }
+
+ if (Math.Abs(newcoords.Y) > 250)
+ {
+ if (newcoords.Y > 0)
+ y += 1;
+ else
+ {
+ y -= 1;
+ }
+ newcoords.Y *= -1;
+ }
+
+ var mapId = seematrix.GetCell(x,y).SeaId;
+
+ var nmapcoords = new MapCoordinates(newcoords, mapId);
+
+ _transform.SetMapCoordinates(ship, nmapcoords);
+
+ }
+
+
}
}
diff --git a/Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs b/Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs
index 1ceecdf2585..5479917fa29 100644
--- a/Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs
+++ b/Content.Shared/Imperial/Medieval/Ships/Sea/SeaComponent.cs
@@ -1,7 +1,7 @@
namespace Content.Shared.Imperial.Medieval.Ships.Sea;
///
-/// This is used for...
+/// Компонент моря
///
[RegisterComponent]
public sealed partial class SeaComponent : Component
From 4db80952ebefcb5ccd20546af786df8b9b4b2f41 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Wed, 18 Mar 2026 19:34:52 +0300
Subject: [PATCH 18/20] =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=BF=D0=BE?=
=?UTF-8?q?=D1=80=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B8=20=D0=BC=D0=BE?=
=?UTF-8?q?=D1=80=D1=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Ships/Sea/Init/MapForSeasInitComponent.cs | 13 ++++
.../Ships/Sea/Init/SeaMatrixInitSystem.cs | 32 +++++++++
.../ShipTeleporting/ShipTeleportSystem.cs | 26 ++++++--
.../Administration/Ships/ShipsCCVars.cs | 66 +++++++++++++++----
4 files changed, 118 insertions(+), 19 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Sea/Init/MapForSeasInitComponent.cs
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Init/MapForSeasInitComponent.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Init/MapForSeasInitComponent.cs
new file mode 100644
index 00000000000..0a8a04af659
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Init/MapForSeasInitComponent.cs
@@ -0,0 +1,13 @@
+namespace Content.Server.Imperial.Medieval.Ships.Sea.Init;
+
+///
+/// This is used for...
+///
+[RegisterComponent]
+public sealed partial class MapForSeasInitComponent : Component
+{
+ [DataField("mapX")]
+ public int MapX { get; set; }
+ [DataField("mapY")]
+ public int MapY { get; set; }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
index a0721dfbaca..37ab0b4bef7 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
@@ -1,5 +1,6 @@
using Content.Server.MagicBarrier.Components;
using Content.Shared.Imperial.Medieval.Ships.Sea;
+using Content.Shared.Interaction;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
@@ -19,6 +20,9 @@ public sealed class SeaMatrixInitSystem : EntitySystem
public override void Initialize()
{
SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnInitMap);
+ SubscribeLocalEvent(OnActivate);
+ SubscribeLocalEvent(OnInteractUsing);
}
private void OnInit(EntityUid uid, MagicBarrierComponent component, ComponentInit args)
@@ -60,6 +64,34 @@ private void OnInit(EntityUid uid, MagicBarrierComponent component, ComponentIni
}
+ private void OnInitMap(EntityUid uid, MapForSeasInitComponent component, ComponentInit args)
+ {
+ if (component.MapX == 0 && component.MapY == 0)
+ return;
+ SetMapPos(uid, component.MapX, component.MapY);
+ }
+
+
+ private void OnActivate(EntityUid uid, MapForSeasInitComponent component, ActivateInWorldEvent args)
+ {
+ SetMapPos(args.Target, component.MapX, component.MapY);
+ }
+
+ private void OnInteractUsing(EntityUid uid, MapForSeasInitComponent component, InteractUsingEvent args)
+ {
+ SetMapPos(args.Target, component.MapX, component.MapY);
+ }
+
+ public void SetMapPos(EntityUid uid, int x, int y)
+ {
+ var mapId = _transform.GetMapId(uid);
+ foreach (var magicBarrier in EntityManager.EntityQuery())
+ {
+ if (magicBarrier.SeaMatrix is null)
+ continue;
+ magicBarrier.SeaMatrix.SetSeaId(x,y,mapId);
+ }
+ }
///
/// ищем мапу либо -1 пишем
///
diff --git a/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
index d71ee711acf..e441841746c 100644
--- a/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/ShipTeleporting/ShipTeleportSystem.cs
@@ -4,6 +4,7 @@
using Content.Shared.Database;
using Content.Shared.Imperial.Medieval.Administration.Ships;
using Content.Shared.Imperial.Medieval.Ships.Sea;
+using Content.Shared.Imperial.Medieval.Ships.ShipDrowning;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
@@ -66,6 +67,9 @@ public override void Update(float frameTime)
private void TeleportShip(EntityUid ship, MapCoordinates coords)
{
+ var mapScale = _cfg.GetCVar(ShipsCCVars.MapScale);
+ var tpRange = _cfg.GetCVar(ShipsCCVars.TeleportRange);
+ var tpDist = mapScale + tpRange;
var newcoords = coords.Position;
foreach (var magicBarrier in EntityManager.EntityQuery())
{
@@ -78,34 +82,46 @@ private void TeleportShip(EntityUid ship, MapCoordinates coords)
var (x, y) = seamap.Value;
- if (Math.Abs(newcoords.X) > 250)
+ if (Math.Abs(newcoords.X) > tpDist)
{
if (newcoords.X > 0)
+ {
x += 1;
+ newcoords.X = -tpDist;
+ }
else
{
x -= 1;
+ newcoords.X = tpDist;
}
- newcoords.X *= -1;
}
- if (Math.Abs(newcoords.Y) > 250)
+ if (Math.Abs(newcoords.Y) > tpDist)
{
if (newcoords.Y > 0)
+ {
y += 1;
+ newcoords.Y = -tpDist;
+ }
+
else
{
y -= 1;
+ newcoords.Y = tpDist;
}
- newcoords.Y *= -1;
}
var mapId = seematrix.GetCell(x,y).SeaId;
+ if (mapId == new MapId(-1))
+ {
+ EnsureComp(ship, out var comp);
+ comp.DrownLevel += (int)Math.Abs(coords.Position.X) + (int)Math.Abs(coords.Position.Y);
+ }
var nmapcoords = new MapCoordinates(newcoords, mapId);
_transform.SetMapCoordinates(ship, nmapcoords);
-
+ break;
}
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
index 68016f2c6c6..b9f7c78fbe2 100644
--- a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -8,48 +8,86 @@ namespace Content.Shared.Imperial.Medieval.Administration.Ships;
[CVarDefs]
public sealed class ShipsCCVars : CVars
{
- // максимальная скорость
+ ///
+ /// максимальная скорость
+ ///
public static readonly CVarDef ShipsMaxSpeed =
CVarDef.Create("ships.maxspeed", 20f, CVar.REPLICATED | CVar.SERVER);
- // как часто меняется ветер
+ ///
+ /// как часто меняется ветер
+ ///
public static readonly CVarDef WindChangeTime =
CVarDef.Create("ships.windchangetime", 1f, CVar.REPLICATED | CVar.SERVER);
- // как часто ветер дует
+ ///
+ /// как часто ветер дует
+ ///
public static readonly CVarDef WindDelay =
CVarDef.Create("ships.winddelay", 1f, CVar.REPLICATED | CVar.SERVER);
- // как часто появляются волны
+ ///
+ /// как часто появляются волны
+ ///
public static readonly CVarDef WaveDelay =
CVarDef.Create("ships.wavedelay", 1f, CVar.REPLICATED | CVar.SERVER);
- // Минимальный уровень для поломки лодки (Шторма если кто не понял)
+ ///
+ /// Минимальный уровень для поломки лодки (Шторма если кто не понял)
+ ///
public static readonly CVarDef WindEnabled =
CVarDef.Create("ships.waveenabled", true, CVar.REPLICATED | CVar.SERVER);
- // сила с которой ветер толкает
+ ///
+ /// сила с которой ветер толкает
+ ///
public static readonly CVarDef WindPower =
CVarDef.Create("ships.windpower", 1f, CVar.REPLICATED | CVar.SERVER);
- // угол поворота ветра
+ ///
+ /// угол поворота ветра
+ ///
public static readonly CVarDef WindRotation =
CVarDef.Create("ships.windrotation", 0f, CVar.REPLICATED | CVar.SERVER);
- // уровень шторма
+ ///
+ /// уровень шторма
+ ///
public static readonly CVarDef StormLevel =
CVarDef.Create("ships.stormlevel", 1f, CVar.REPLICATED | CVar.SERVER);
- // скорость с которой волна спавнится
+ ///
+ /// скорость с которой волна спавнится
+ ///
public static readonly CVarDef WaveForce =
CVarDef.Create("ships.waveforce", 1f, CVar.REPLICATED | CVar.SERVER);
- // радиус спавна волн
+ ///
+ /// радиус спавна волн
+ ///
public static readonly CVarDef WaveSpawnRange =
CVarDef.Create("ships.wavespawnrange", 40f, CVar.REPLICATED | CVar.SERVER);
- // угол разброса волн
+ ///
+ /// угол разброса волн
+ ///
public static readonly CVarDef WaveSpawnAngle =
CVarDef.Create("ships.wavespawnangle", 10f, CVar.REPLICATED | CVar.SERVER);
- // в каком радиусе ломает волна
+ ///
+ /// в каком радиусе ломает волна
+ ///
public static readonly CVarDef WaveRadiusTiles =
CVarDef.Create("ships.waveradiustiles", 3f, CVar.REPLICATED | CVar.SERVER);
- // какое максимальное количество тайлов может сломать волна
+ ///
+ /// какое максимальное количество тайлов может сломать волна
+ ///
public static readonly CVarDef WaveMaxBreakCount =
CVarDef.Create("ships.wavemaxbreakcount", 3, CVar.REPLICATED | CVar.SERVER);
- // Минимальный уровень для поломки лодки (Шторма если кто не понял)
+ ///
+ /// Минимальный уровень для поломки лодки (Шторма если кто не понял)
+ ///
public static readonly CVarDef WaveMinToBreakLevel =
CVarDef.Create("ships.wavemintobreaklevel", 2, CVar.REPLICATED | CVar.SERVER);
+ ///
+ /// размер карты
+ ///
+ public static readonly CVarDef MapScale =
+ CVarDef.Create("ships.mapscale", 200, CVar.REPLICATED | CVar.SERVER);
+ ///
+ /// радиус с которого телепортирует корабль
+ ///
+ public static readonly CVarDef TeleportRange =
+ CVarDef.Create("ships.teleportrange", 50, CVar.REPLICATED | CVar.SERVER);
}
From a8e8259269f981d1da5beaf8ebb240a5814a2f04 Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Wed, 18 Mar 2026 22:06:25 +0300
Subject: [PATCH 19/20] =?UTF-8?q?=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0?=
=?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BE=D1=81=D1=82=D1=80=D0=BE=D0=B2=D0=BE?=
=?UTF-8?q?=D0=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Ships/Sea/Generation/IslandPrototype.cs | 33 ++++
.../Sea/Generation/SeasGenerationSystem.cs | 182 +++++++++++++++++-
.../Ships/Sea/Init/SeaMatrixInitSystem.cs | 42 +---
.../Administration/Ships/ShipsCCVars.cs | 2 +-
.../Medieval/Seas/Islands/Islands.yml | 20 ++
5 files changed, 232 insertions(+), 47 deletions(-)
create mode 100644 Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs
create mode 100644 Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs
new file mode 100644
index 00000000000..131219feb30
--- /dev/null
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs
@@ -0,0 +1,33 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Imperial.Medieval.Ships.Sea.Generation;
+
+///
+/// Прототип острова — содержит конфигурацию для генерации.
+/// Используется для определения типа, размера и других параметров.
+///
+[Prototype("island")]
+public sealed partial class IslandPrototype : IPrototype
+{
+ ///
+ [IdDataField]
+ public string ID { get; } = default!;
+
+ ///
+ /// Размер острова в тайлах (например, 1 = 1x1, 2 = 2x2, 3 = 3x3).
+ ///
+ [DataField("size", required: true)]
+ public int Size { get; private set; }
+
+ ///
+ /// Множитель веса для случайной генерации (если нужно балансировать частоту).
+ ///
+ [DataField("spawnWeight")]
+ public int SpawnWeight { get; private set; } = 1;
+
+ ///
+ /// Опциональное имя для логирования или интерфейса (не используется в спавне).
+ ///
+ [DataField("name", required: false)]
+ public string? Name { get; private set; }
+}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
index 7fa7201d13c..ed44b180c5f 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
@@ -1,13 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Content.Server.Imperial.Medieval.Ships.Sea.Init;
+using Content.Server.MagicBarrier.Components;
+using Content.Shared.Imperial.Medieval.Ships.Sea;
+using Robust.Server.GameObjects;
+using Robust.Shared.EntitySerialization.Systems;
+using Robust.Shared.Map;
+using Robust.Shared.Random;
+using Robust.Shared.Prototypes;
+
namespace Content.Server.Imperial.Medieval.Ships.Sea.Generation;
-///
-/// This handles...
-///
public sealed class SeasGenerationSystem : EntitySystem
{
- ///
+ [Dependency] private readonly MapLoaderSystem _mapLoader = default!;
+ [Dependency] private readonly SharedMapSystem _map = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly MetaDataSystem _metaData = default!;
+ [Dependency] private readonly SeaMatrixInitSystem _seaMatrix = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!; // 🔥 НОВЫЙ ДЕПЕНДЕНС
+
+ private const int MapMin = -75;
+ private const int MapMax = 75;
+
+ // Используем прототипы вместо строк
+ private static readonly (string PrototypeId, int Count)[] IslandConfig = {
+ ("PirateIsland", 1), // 1 большой
+ ("FrendlyIslands", 2), // 2 средних
+ ("VolcanicIsland", 10) // 10 мелких
+ };
+
public override void Initialize()
{
-
+ SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnSeasGeneration);
+ }
+
+ private void OnInit(EntityUid uid, MagicBarrierComponent component, ComponentInit args)
+ {
+ if (component.SeaMatrix == null)
+ component.SeaMatrix = new SeaMatrix(new List<(int x, int y)>
+ {
+ (2, 2), (2, 3), (2, 4),
+ (3, 2), (3, 3), (3, 4),
+ (4, 2), (4, 3), (4, 4),
+ });
+
+ if (component.SeaInitalazed) return;
+
+ var seaMatrix = component.SeaMatrix;
+
+ // Создаем 25 карт моря (5x5)
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ if (!seaMatrix.NeedsGeneration(x, y)) continue;
+
+ var mapUid = _map.CreateMap();
+ _metaData.SetEntityName(mapUid, $"Море {x} {y}");
+ var mapId = _transform.GetMapId(mapUid);
+ AddComp(mapUid);
+ seaMatrix.SetSeaId(x, y, mapId);
+ seaMatrix.SetGenerated(x, y, true);
+ }
+ }
+
+ // ✅ ГЕНЕРИРУЕМ ОСТРОВА С ИСПОЛЬЗОВАНИЕМ IPrototypeManager
+ GenerateIslandsOnSeaMaps(seaMatrix);
+
+ component.SeaInitalazed = true;
+ }
+
+ ///
+ /// Генерирует острова, используя IPrototypeManager и конфигурацию по ID.
+ /// Все острова размещаются в общем пространстве [-75, 75], без пересечений.
+ ///
+ private void GenerateIslandsOnSeaMaps(SeaMatrix seaMatrix)
+ {
+ var generatedObjects = new List();
+ var occupiedTiles = new HashSet<(int X, int Y)>();
+
+ // Собираем все MapId карт моря
+ var seaMapIds = new List();
+ for (int x = 0; x < 5; x++)
+ {
+ for (int y = 0; y < 5; y++)
+ {
+ var cell = seaMatrix.GetCell(x, y);
+ if (cell.NeedGenerate && !(cell.SeaId == new MapId(-1)))
+ seaMapIds.Add(cell.SeaId);
+ }
+ }
+
+ if (seaMapIds.Count == 0)
+ {
+ Logger.Warning("No sea maps found to generate islands on!");
+ return;
+ }
+
+ // Проходим по конфигурации островов
+ foreach (var (prototypeId, count) in IslandConfig)
+ {
+ // Проверяем, существует ли прототип
+ if (!_prototypeManager.TryIndex(prototypeId, out var prototype))
+ {
+ Logger.Warning($"Island prototype '{prototypeId}' not found! Skipping.");
+ continue;
+ }
+
+ for (int i = 0; i < count; i++)
+ {
+ int attempts = 0;
+ const int maxAttempts = 100;
+ EntityUid? newObj = null;
+
+ while (++attempts <= maxAttempts)
+ {
+ // Выбираем случайную карту моря
+ var targetMapId = seaMapIds[_random.Next(seaMapIds.Count)];
+
+ // Случайная позиция на карте
+ int x = _random.Next(MapMin, MapMax - prototype.Size + 1);
+ int y = _random.Next(MapMin, MapMax - prototype.Size + 1);
+
+ // Проверяем пересечения
+ bool overlaps = false;
+ var newTiles = new List<(int X, int Y)>();
+
+ for (int dx = 0; dx < prototype.Size; dx++)
+ {
+ for (int dy = 0; dy < prototype.Size; dy++)
+ {
+ var tile = (x + dx, y + dy);
+ if (occupiedTiles.Contains(tile))
+ {
+ overlaps = true;
+ break;
+ }
+ newTiles.Add(tile);
+ }
+ if (overlaps)
+ break;
+ }
+
+ if (!overlaps)
+ {
+ // ✅ СПАВН С ПРОТОТИПОМ, а не строкой!
+ newObj = EntityManager.SpawnEntity(prototypeId, new MapCoordinates(x, y, targetMapId));
+ // _mapLoader.TryLoadGrid(targetMapId, );
+ if (newObj.HasValue)
+ {
+ generatedObjects.Add(newObj.Value);
+ foreach (var tile in newTiles)
+ occupiedTiles.Add(tile);
+ break; // Успешно
+ }
+ }
+ }
+
+ if (attempts > maxAttempts)
+ {
+ Logger.Warning($"Failed to generate {prototypeId} after {maxAttempts} attempts.");
+ }
+ }
+ }
+
+ Logger.Info($"Successfully generated {generatedObjects.Count} islands across {seaMapIds.Count} sea maps.");
+ }
+
+ public sealed class SeasGenerationEvent
+ {
+ public MapId MapId { get; set; }
+ public int Count { get; set; }
+ public string Prototype { get; set; } = "Reef";
+ }
+
+ private void OnSeasGeneration(SeasGenerationEvent ev)
+ {
+ // Оставлено для будущего расширения
}
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
index 37ab0b4bef7..ea6a20cc3c4 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Init/SeaMatrixInitSystem.cs
@@ -15,55 +15,15 @@ public sealed class SeaMatrixInitSystem : EntitySystem
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly EntityManager _entManager = default!;
- [Dependency] private readonly MetaDataSystem _metaData = default!;
+
///
public override void Initialize()
{
- SubscribeLocalEvent(OnInit);
SubscribeLocalEvent(OnInitMap);
SubscribeLocalEvent(OnActivate);
SubscribeLocalEvent(OnInteractUsing);
}
- private void OnInit(EntityUid uid, MagicBarrierComponent component, ComponentInit args)
- {
- if (component.SeaMatrix == null)
- component.SeaMatrix = new SeaMatrix(new List<(int x, int y)>
- {
- (2, 2), (2, 3), (2, 4),
- (3, 2), (3, 3), (3, 4),
- (4, 2), (4, 3), (4, 4),
- });
-
- if (component.SeaInitalazed)
- return;
-
- var seamat = component.SeaMatrix;
-
- for (int x = 0; x < 5; x++)
- {
- for (int y = 0; y < 5; y++)
- {
- if (!seamat.NeedsGeneration(x, y))
- {
- if (seamat.GetCell(x, y).SeaId == new MapId(1))
- {
- seamat.SetSeaId(x, y, TryFoundMap(x,y));
- }
- }
- var mapUid = _map.CreateMap();
- _metaData.SetEntityName(mapUid, $"Море {x} {y}");
- var mapId = _transform.GetMapId(mapUid);
- AddComp(mapUid);
- seamat.SetSeaId(x,y,mapId);
- seamat.SetGenerated(x,y,true);
-
- }
- }
-
-
- }
-
private void OnInitMap(EntityUid uid, MapForSeasInitComponent component, ComponentInit args)
{
if (component.MapX == 0 && component.MapY == 0)
diff --git a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
index b9f7c78fbe2..4c9030c5ade 100644
--- a/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
+++ b/Content.Shared/Imperial/Medieval/Administration/Ships/ShipsCCVars.cs
@@ -82,7 +82,7 @@ public sealed class ShipsCCVars : CVars
/// размер карты
///
public static readonly CVarDef MapScale =
- CVarDef.Create("ships.mapscale", 200, CVar.REPLICATED | CVar.SERVER);
+ CVarDef.Create("ships.mapscale", 100, CVar.REPLICATED | CVar.SERVER);
///
/// радиус с которого телепортирует корабль
///
diff --git a/Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml b/Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml
new file mode 100644
index 00000000000..c8483534e0c
--- /dev/null
+++ b/Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml
@@ -0,0 +1,20 @@
+- type: island
+ id: PirateIslands
+ size: 20
+ spawnWeight: 20
+ name: "Пиратский остров"
+
+- type: island
+ id: FrendlyIslands
+ name: "Дружелюбный остров"
+ size: 5
+ spawnWeight: 5
+
+- type: island
+ id: VolcanicIsland
+ name: "Вулканический остров"
+ size: 3
+ spawnWeight: 8
+
+
+
From 9f0b6907db26339cee9f53a7f2128f8494fd5efc Mon Sep 17 00:00:00 2001
From: Magic0stick <77047717+Magic0stick@users.noreply.github.com>
Date: Thu, 19 Mar 2026 20:56:28 +0300
Subject: [PATCH 20/20] =?UTF-8?q?=D0=A3=D1=80=D0=B0=D0=B0=20=D0=B3=D0=BE?=
=?UTF-8?q?=D1=82=D0=BE=D0=B2=D0=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Ships/Sea/Generation/IslandPrototype.cs | 7 +++++++
.../Ships/Sea/Generation/SeasGenerationSystem.cs | 13 +++++++------
.../Imperial/Medieval/Seas/Islands/Islands.yml | 3 +++
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs
index 131219feb30..014f9779fbe 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/IslandPrototype.cs
@@ -30,4 +30,11 @@ public sealed partial class IslandPrototype : IPrototype
///
[DataField("name", required: false)]
public string? Name { get; private set; }
+
+ ///
+ /// Опциональное имя для логирования или интерфейса (не используется в спавне).
+ ///
+ [DataField("path")]
+ public string? Path { get; private set; }
+
}
diff --git a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
index ed44b180c5f..8477e4f0213 100644
--- a/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
+++ b/Content.Server/Imperial/Medieval/Ships/Sea/Generation/SeasGenerationSystem.cs
@@ -1,14 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Numerics;
using Content.Server.Imperial.Medieval.Ships.Sea.Init;
using Content.Server.MagicBarrier.Components;
using Content.Shared.Imperial.Medieval.Ships.Sea;
using Robust.Server.GameObjects;
using Robust.Shared.EntitySerialization.Systems;
using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
using Robust.Shared.Random;
using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
namespace Content.Server.Imperial.Medieval.Ships.Sea.Generation;
@@ -57,7 +60,8 @@ private void OnInit(EntityUid uid, MagicBarrierComponent component, ComponentIni
{
for (int y = 0; y < 5; y++)
{
- if (!seaMatrix.NeedsGeneration(x, y)) continue;
+ if (!seaMatrix.NeedsGeneration(x, y))
+ continue;
var mapUid = _map.CreateMap();
_metaData.SetEntityName(mapUid, $"Море {x} {y}");
@@ -105,7 +109,7 @@ private void GenerateIslandsOnSeaMaps(SeaMatrix seaMatrix)
foreach (var (prototypeId, count) in IslandConfig)
{
// Проверяем, существует ли прототип
- if (!_prototypeManager.TryIndex(prototypeId, out var prototype))
+ if (!_prototypeManager.TryIndex(prototypeId, out var prototype) || prototype.Path == null)
{
Logger.Warning($"Island prototype '{prototypeId}' not found! Skipping.");
continue;
@@ -115,7 +119,6 @@ private void GenerateIslandsOnSeaMaps(SeaMatrix seaMatrix)
{
int attempts = 0;
const int maxAttempts = 100;
- EntityUid? newObj = null;
while (++attempts <= maxAttempts)
{
@@ -148,9 +151,7 @@ private void GenerateIslandsOnSeaMaps(SeaMatrix seaMatrix)
if (!overlaps)
{
- // ✅ СПАВН С ПРОТОТИПОМ, а не строкой!
- newObj = EntityManager.SpawnEntity(prototypeId, new MapCoordinates(x, y, targetMapId));
- // _mapLoader.TryLoadGrid(targetMapId, );
+ _mapLoader.TryLoadGrid(targetMapId, new ResPath(prototype.Path), out var newObj, offset: new Vector2(x,y));
if (newObj.HasValue)
{
generatedObjects.Add(newObj.Value);
diff --git a/Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml b/Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml
index c8483534e0c..cf44d1adff3 100644
--- a/Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml
+++ b/Resources/Prototypes/Imperial/Medieval/Seas/Islands/Islands.yml
@@ -3,18 +3,21 @@
size: 20
spawnWeight: 20
name: "Пиратский остров"
+ path: /Ships/Victoria.yml
- type: island
id: FrendlyIslands
name: "Дружелюбный остров"
size: 5
spawnWeight: 5
+ path: /Ships/Victoria.yml
- type: island
id: VolcanicIsland
name: "Вулканический остров"
size: 3
spawnWeight: 8
+ path: /Ships/Victoria.yml