From df3ad96bba34008a8ff63103196ad826a3dcc6ec Mon Sep 17 00:00:00 2001 From: "Dolzhukov, Viktor" Date: Sun, 27 Sep 2026 09:55:12 +0500 Subject: [PATCH] p36.10 Sentry turrets revamp --- .../Modules/EntitiesModule.cs | 3 + src/Perpetuum.ExportedTypes/AggregateField.cs | 18 ++++ src/Perpetuum.ExportedTypes/CategoryFlags.cs | 3 +- src/Perpetuum/Modules/ActiveModule.cs | 2 + .../ModuleProperties/OptimalRangeProperty.cs | 1 + .../AssaultRemoteControllerModule.cs | 25 +++++ .../EngineeringRemoteControllerModule.cs | 100 ++++++++++++++++++ .../HunterRemoteControllerModule.cs | 25 +++++ .../IndustrialRemoteControllerModule.cs | 25 +++++ .../RemoteControl/RemoteControllerModule.cs | 30 +----- .../SupportRemoteControllerModule.cs | 25 +++++ .../TacticalRemoteControllerModule.cs | 25 +++++ .../Modules/Weapons/MissileWeaponModule.cs | 2 + src/Perpetuum/Modules/Weapons/WeaponModule.cs | 6 ++ src/Perpetuum/Units/Unit.cs | 2 + .../Units/UnitProperties/ArmorMaxProperty.cs | 1 + .../UnitProperties/LockingTimeProperty.cs | 3 +- src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs | 16 ++- .../NpcSystem/AI/SentryTurretCombatAI.cs | 24 ++++- .../NpcSystem/AI/SentryTurretRetreatAI.cs | 34 ++++++ .../Zones/RemoteControl/CombatDrone.cs | 10 +- .../Zones/RemoteControl/IndustrialDrone.cs | 2 - .../RemoteControl/RemoteControlledCreature.cs | 7 +- .../Zones/RemoteControl/SentryTurret.cs | 46 ++++++++ 24 files changed, 396 insertions(+), 39 deletions(-) create mode 100644 src/Perpetuum/Modules/RemoteControl/EngineeringRemoteControllerModule.cs create mode 100644 src/Perpetuum/Zones/NpcSystem/AI/SentryTurretRetreatAI.cs diff --git a/src/Perpetuum.Bootstrapper/Modules/EntitiesModule.cs b/src/Perpetuum.Bootstrapper/Modules/EntitiesModule.cs index 0c02826b..1a251eff 100644 --- a/src/Perpetuum.Bootstrapper/Modules/EntitiesModule.cs +++ b/src/Perpetuum.Bootstrapper/Modules/EntitiesModule.cs @@ -239,6 +239,7 @@ protected override void Load(ContainerBuilder builder) RegisterModule(builder); RegisterModule(builder); RegisterModule(builder); + RegisterModule(builder); RegisterModule(builder); RegisterModule(builder); RegisterModule(builder); @@ -400,6 +401,7 @@ void ByNamePatternAndFlag(string substr, CategoryFlags cf, params Parameter[] ByCategoryFlags(CategoryFlags.cf_industrial_drones_units); ByCategoryFlags(CategoryFlags.cf_support_drones_units); ByCategoryFlags(CategoryFlags.cf_hunter_drones_units); + ByCategoryFlags(CategoryFlags.cf_sentry_turret_units); ByCategoryFlags(CategoryFlags.cf_remote_commands); ByCategoryFlags(CategoryFlags.cf_mining_probe_ammo_tile); ByCategoryFlags(CategoryFlags.cf_mining_probe_ammo_one_tile); @@ -501,6 +503,7 @@ void ByNamePatternAndFlag(string substr, CategoryFlags cf, params Parameter[] ByCategoryFlags(CategoryFlags.cf_industrial_remote_controllers, new NamedParameter("ammoCategoryFlags", CategoryFlags.cf_industrial_drones_units)); ByCategoryFlags(CategoryFlags.cf_support_remote_controllers, new NamedParameter("ammoCategoryFlags", CategoryFlags.cf_support_drones_units)); ByCategoryFlags(CategoryFlags.cf_hunter_remote_controllers, new NamedParameter("ammoCategoryFlags", CategoryFlags.cf_hunter_drones_units)); + ByCategoryFlags(CategoryFlags.cf_engineering_remote_controllers, new NamedParameter("ammoCategoryFlags", CategoryFlags.cf_sentry_turret_units)); ByCategoryFlags(CategoryFlags.cf_webber); ByCategoryFlags(CategoryFlags.cf_sensor_dampeners); ByCategoryFlags(CategoryFlags.cf_remote_sensor_boosters); diff --git a/src/Perpetuum.ExportedTypes/AggregateField.cs b/src/Perpetuum.ExportedTypes/AggregateField.cs index b3037c80..c7d35e10 100644 --- a/src/Perpetuum.ExportedTypes/AggregateField.cs +++ b/src/Perpetuum.ExportedTypes/AggregateField.cs @@ -522,5 +522,23 @@ public enum AggregateField self_destruct_config_damage_explosive = 762, self_destruct_config_damage_kinetic = 763, self_destruct_config_damage_thermal = 764, + turret_amplification_damage_modifier = 765, + turret_amplification_damage_modifier_modifier = 766, + turret_amplification_locking_time_modifier = 767, + turret_amplification_locking_time_modifier_modifier = 768, + turret_amplification_cycle_time_modifier = 769, + turret_amplification_cycle_time_modifier_modifier = 770, + turret_amplification_armor_max_modifier = 771, + turret_amplification_armor_max_modifier_modifier = 772, + turret_amplification_core_max_modifier = 773, + turret_amplification_core_max_modifier_modifier = 774, + turret_amplification_core_recharge_time_modifier = 775, + turret_amplification_core_recharge_time_modifier_modifier = 776, + turret_amplification_long_range_modifier = 777, + turret_amplification_long_range_modifier_modifier = 778, + turret_amplification_accuracy_modifier = 779, + turret_amplification_accuracy_modifier_modifier = 780, + turret_amplification_reactor_radiation_modifier = 781, + turret_amplification_reactor_radiation_modifier_modifier = 782 } } diff --git a/src/Perpetuum.ExportedTypes/CategoryFlags.cs b/src/Perpetuum.ExportedTypes/CategoryFlags.cs index 62b92f52..c5661ce6 100644 --- a/src/Perpetuum.ExportedTypes/CategoryFlags.cs +++ b/src/Perpetuum.ExportedTypes/CategoryFlags.cs @@ -59,6 +59,7 @@ public enum CategoryFlags : long cf_support_drones = 0x0000000000031101, cf_attack_drones = 0x0000000000041101, cf_hunter_drones = 0x0000000000051101, + cf_sentry_turrets = 0x0000000000061101, cf_ammo = 0x000000000000000A, cf_railgun_ammo = 0x000000000000010A, @@ -223,6 +224,7 @@ public enum CategoryFlags : long cf_remote_command_translators = 0x00000000050C040F, cf_hunter_remote_controllers = 0x00000000060C040F, + cf_engineering_remote_controllers = 0x00000000070C040F, cf_electronic_warfare_equipment = 0x000000000000050F, cf_webber = 0x000000000001050F, @@ -618,7 +620,6 @@ public enum CategoryFlags : long cf_gate = 0x0000000000000A92, cf_rifts = 0x0000000000000B92, cf_portals = 0x0000000000000C92, - cf_sentry_turrets = 0x0000000000000D92, cf_mining_turrets = 0x0000000000000E92, cf_harvesting_turrets = 0x0000000000000F92, cf_combat_drones = 0x0000000000001092, diff --git a/src/Perpetuum/Modules/ActiveModule.cs b/src/Perpetuum/Modules/ActiveModule.cs index 18ba4406..1d0e148d 100644 --- a/src/Perpetuum/Modules/ActiveModule.cs +++ b/src/Perpetuum/Modules/ActiveModule.cs @@ -269,6 +269,7 @@ protected override void OnUpdateProperty(AggregateField field) case AggregateField.effect_weapon_cycle_time_modifier: case AggregateField.effect_gathering_cycle_time_modifier: case AggregateField.drone_amplification_cycle_time_modifier: + case AggregateField.turret_amplification_cycle_time_modifier: case AggregateField.drone_amplification_remote_repair_cycle_time_modifier: { cycleTime.Update(); @@ -281,6 +282,7 @@ protected override void OnUpdateProperty(AggregateField field) case AggregateField.module_missile_range_modifier: case AggregateField.effect_missile_range_modifier: case AggregateField.drone_amplification_long_range_modifier: + case AggregateField.turret_amplification_long_range_modifier: case AggregateField.effect_dreadnought_optimal_range_modifier: { optimalRange.Update(); diff --git a/src/Perpetuum/Modules/ModuleProperties/OptimalRangeProperty.cs b/src/Perpetuum/Modules/ModuleProperties/OptimalRangeProperty.cs index adfbaf8f..cededec6 100644 --- a/src/Perpetuum/Modules/ModuleProperties/OptimalRangeProperty.cs +++ b/src/Perpetuum/Modules/ModuleProperties/OptimalRangeProperty.cs @@ -13,6 +13,7 @@ public OptimalRangeProperty(ActiveModule module) : base(module, AggregateField.o _module = module; AddEffectModifier(AggregateField.effect_optimal_range_modifier); AddEffectModifier(AggregateField.drone_amplification_long_range_modifier); + AddEffectModifier(AggregateField.turret_amplification_long_range_modifier); AddEffectModifier(AggregateField.effect_dreadnought_optimal_range_modifier); } diff --git a/src/Perpetuum/Modules/RemoteControl/AssaultRemoteControllerModule.cs b/src/Perpetuum/Modules/RemoteControl/AssaultRemoteControllerModule.cs index c82c5380..fb944aa9 100644 --- a/src/Perpetuum/Modules/RemoteControl/AssaultRemoteControllerModule.cs +++ b/src/Perpetuum/Modules/RemoteControl/AssaultRemoteControllerModule.cs @@ -15,6 +15,13 @@ public class AssaultRemoteControllerModule : RemoteControllerModule private readonly ModuleProperty droneLongRange; private readonly ModuleProperty droneAccuracy; + private readonly ModuleProperty droneLockingTime; + private readonly ModuleProperty droneArmorMax; + private readonly ModuleProperty droneCoreMax; + private readonly ModuleProperty droneCoreRechargeTime; + private readonly ModuleProperty droneSpeedMax; + private readonly ModuleProperty droneReactorRadiation; + public AssaultRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryFlags) { droneDamage = new ModuleProperty(this, AggregateField.drone_amplification_damage_modifier); @@ -27,6 +34,24 @@ public AssaultRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(amm AddProperty(droneLongRange); droneAccuracy = new ModuleProperty(this, AggregateField.drone_amplification_accuracy_modifier); AddProperty(droneAccuracy); + + droneLockingTime = new ModuleProperty(this, AggregateField.drone_amplification_locking_time_modifier); + AddProperty(droneLockingTime); + + droneArmorMax = new ModuleProperty(this, AggregateField.drone_amplification_armor_max_modifier); + AddProperty(droneArmorMax); + + droneCoreMax = new ModuleProperty(this, AggregateField.drone_amplification_core_max_modifier); + AddProperty(droneCoreMax); + + droneCoreRechargeTime = new ModuleProperty(this, AggregateField.drone_amplification_core_recharge_time_modifier); + AddProperty(droneCoreRechargeTime); + + droneSpeedMax = new ModuleProperty(this, AggregateField.drone_amplification_speed_max_modifier); + AddProperty(droneSpeedMax); + + droneReactorRadiation = new ModuleProperty(this, AggregateField.drone_amplification_reactor_radiation_modifier); + AddProperty(droneReactorRadiation); } public override RemoteControlledCreature CreateAndConfigureRcu(RemoteControlledUnit ammo) diff --git a/src/Perpetuum/Modules/RemoteControl/EngineeringRemoteControllerModule.cs b/src/Perpetuum/Modules/RemoteControl/EngineeringRemoteControllerModule.cs new file mode 100644 index 00000000..bbfcff66 --- /dev/null +++ b/src/Perpetuum/Modules/RemoteControl/EngineeringRemoteControllerModule.cs @@ -0,0 +1,100 @@ +using Perpetuum.EntityFramework; +using Perpetuum.ExportedTypes; +using Perpetuum.Items; +using Perpetuum.Modules.ModuleProperties; +using Perpetuum.Zones.Effects; +using Perpetuum.Zones.NpcSystem.AI.Behaviors; +using Perpetuum.Zones.RemoteControl; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perpetuum.Modules.RemoteControl +{ + public class EngineeringRemoteControllerModule : RemoteControllerModule + { + private readonly ModuleProperty turretDamage; + private readonly ModuleProperty turretCycleTime; + private readonly ModuleProperty turretLongRange; + private readonly ModuleProperty turretAccuracy; + + private readonly ModuleProperty turretLockingTime; + private readonly ModuleProperty turretArmorMax; + private readonly ModuleProperty turretCoreMax; + private readonly ModuleProperty turretCoreRechargeTime; + private readonly ModuleProperty turretReactorRadiation; + + public EngineeringRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryFlags) + { + turretDamage = new ModuleProperty(this, AggregateField.turret_amplification_damage_modifier); + AddProperty(turretDamage); + + turretCycleTime = new ModuleProperty(this, AggregateField.turret_amplification_cycle_time_modifier); + AddProperty(turretCycleTime); + + turretLongRange = new ModuleProperty(this, AggregateField.turret_amplification_long_range_modifier); + AddProperty(turretLongRange); + turretAccuracy = new ModuleProperty(this, AggregateField.turret_amplification_accuracy_modifier); + AddProperty(turretAccuracy); + + turretLockingTime = new ModuleProperty(this, AggregateField.turret_amplification_locking_time_modifier); + AddProperty(turretLockingTime); + + turretArmorMax = new ModuleProperty(this, AggregateField.turret_amplification_armor_max_modifier); + AddProperty(turretArmorMax); + + turretCoreMax = new ModuleProperty(this, AggregateField.turret_amplification_core_max_modifier); + AddProperty(turretCoreMax); + + turretCoreRechargeTime = new ModuleProperty(this, AggregateField.turret_amplification_core_recharge_time_modifier); + AddProperty(turretCoreRechargeTime); + + turretReactorRadiation = new ModuleProperty(this, AggregateField.turret_amplification_reactor_radiation_modifier); + AddProperty(turretReactorRadiation); + } + + public override RemoteControlledCreature CreateAndConfigureRcu(RemoteControlledUnit ammo) + { + RemoteControlledCreature remoteControlledCreature = null; + if (ammo.ED.Options.TurretType == TurretType.Sentry) + { + remoteControlledCreature = (SentryTurret)Factory.CreateWithRandomEID(ammo.ED.Options.TurretId); + remoteControlledCreature.Behavior = Behavior.Create(BehaviorType.RemoteControlledTurret); + remoteControlledCreature.GuardRange = 5; + } + else + { + _ = PerpetuumException.Create(ErrorCodes.InvalidAmmoDefinition); + } + + return remoteControlledCreature; + } + + protected override void SetupEffect(EffectBuilder effectBuilder) + { + double damageModifier = GetPropertyModifier(AggregateField.turret_amplification_damage_modifier).Value; + double lockingTimeModifier = GetPropertyModifier(AggregateField.turret_amplification_locking_time_modifier).Value; + double cycleTimeModifier = GetPropertyModifier(AggregateField.turret_amplification_cycle_time_modifier).Value; + double armorMaxModifier = GetPropertyModifier(AggregateField.turret_amplification_armor_max_modifier).Value; + double coreMaxModifier = GetPropertyModifier(AggregateField.turret_amplification_core_max_modifier).Value; + double coreRechargeTimeModifier = GetPropertyModifier(AggregateField.turret_amplification_core_recharge_time_modifier).Value; + double longRangeModifier = GetPropertyModifier(AggregateField.turret_amplification_long_range_modifier).Value; + double accuracyModifier = GetPropertyModifier(AggregateField.turret_amplification_accuracy_modifier).Value; + double reactorRadiationModifier = GetPropertyModifier(AggregateField.turret_amplification_reactor_radiation_modifier).Value; + + _ = effectBuilder + .SetType(EffectType.drone_amplification) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_damage_modifier, AggregateFormula.Modifier, damageModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_locking_time_modifier, AggregateFormula.Inverse, lockingTimeModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_cycle_time_modifier, AggregateFormula.Inverse, cycleTimeModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_armor_max_modifier, AggregateFormula.Modifier, armorMaxModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_core_max_modifier, AggregateFormula.Modifier, coreMaxModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_core_recharge_time_modifier, AggregateFormula.Inverse, coreRechargeTimeModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_long_range_modifier, AggregateFormula.Modifier, longRangeModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_accuracy_modifier, AggregateFormula.Inverse, accuracyModifier)) + .WithPropertyModifier(new ItemPropertyModifier(AggregateField.turret_amplification_reactor_radiation_modifier, AggregateFormula.Inverse, reactorRadiationModifier)); + } + } +} diff --git a/src/Perpetuum/Modules/RemoteControl/HunterRemoteControllerModule.cs b/src/Perpetuum/Modules/RemoteControl/HunterRemoteControllerModule.cs index 247bef7f..c6e20613 100644 --- a/src/Perpetuum/Modules/RemoteControl/HunterRemoteControllerModule.cs +++ b/src/Perpetuum/Modules/RemoteControl/HunterRemoteControllerModule.cs @@ -18,10 +18,35 @@ public class HunterRemoteControllerModule : RemoteControllerModule { private readonly ModuleProperty detectionRange; + private readonly ModuleProperty droneLockingTime; + private readonly ModuleProperty droneArmorMax; + private readonly ModuleProperty droneCoreMax; + private readonly ModuleProperty droneCoreRechargeTime; + private readonly ModuleProperty droneSpeedMax; + private readonly ModuleProperty droneReactorRadiation; + public HunterRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryFlags) { detectionRange = new ModuleProperty(this, AggregateField.detection_range); AddProperty(detectionRange); + + droneLockingTime = new ModuleProperty(this, AggregateField.drone_amplification_locking_time_modifier); + AddProperty(droneLockingTime); + + droneArmorMax = new ModuleProperty(this, AggregateField.drone_amplification_armor_max_modifier); + AddProperty(droneArmorMax); + + droneCoreMax = new ModuleProperty(this, AggregateField.drone_amplification_core_max_modifier); + AddProperty(droneCoreMax); + + droneCoreRechargeTime = new ModuleProperty(this, AggregateField.drone_amplification_core_recharge_time_modifier); + AddProperty(droneCoreRechargeTime); + + droneSpeedMax = new ModuleProperty(this, AggregateField.drone_amplification_speed_max_modifier); + AddProperty(droneSpeedMax); + + droneReactorRadiation = new ModuleProperty(this, AggregateField.drone_amplification_reactor_radiation_modifier); + AddProperty(droneReactorRadiation); } protected override void SetupEffect(EffectBuilder effectBuilder) diff --git a/src/Perpetuum/Modules/RemoteControl/IndustrialRemoteControllerModule.cs b/src/Perpetuum/Modules/RemoteControl/IndustrialRemoteControllerModule.cs index 85245075..22d10623 100644 --- a/src/Perpetuum/Modules/RemoteControl/IndustrialRemoteControllerModule.cs +++ b/src/Perpetuum/Modules/RemoteControl/IndustrialRemoteControllerModule.cs @@ -13,6 +13,13 @@ public class IndustrialRemoteControllerModule : RemoteControllerModule private readonly ModuleProperty droneMiningAmount; private readonly ModuleProperty droneHarvestingAmount; + private readonly ModuleProperty droneLockingTime; + private readonly ModuleProperty droneArmorMax; + private readonly ModuleProperty droneCoreMax; + private readonly ModuleProperty droneCoreRechargeTime; + private readonly ModuleProperty droneSpeedMax; + private readonly ModuleProperty droneReactorRadiation; + public IndustrialRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryFlags) { droneMiningAmount = new ModuleProperty(this, AggregateField.drone_amplification_mining_amount_modifier); @@ -20,6 +27,24 @@ public IndustrialRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base( droneHarvestingAmount = new ModuleProperty(this, AggregateField.drone_amplification_harvesting_amount_modifier); AddProperty(droneHarvestingAmount); + + droneLockingTime = new ModuleProperty(this, AggregateField.drone_amplification_locking_time_modifier); + AddProperty(droneLockingTime); + + droneArmorMax = new ModuleProperty(this, AggregateField.drone_amplification_armor_max_modifier); + AddProperty(droneArmorMax); + + droneCoreMax = new ModuleProperty(this, AggregateField.drone_amplification_core_max_modifier); + AddProperty(droneCoreMax); + + droneCoreRechargeTime = new ModuleProperty(this, AggregateField.drone_amplification_core_recharge_time_modifier); + AddProperty(droneCoreRechargeTime); + + droneSpeedMax = new ModuleProperty(this, AggregateField.drone_amplification_speed_max_modifier); + AddProperty(droneSpeedMax); + + droneReactorRadiation = new ModuleProperty(this, AggregateField.drone_amplification_reactor_radiation_modifier); + AddProperty(droneReactorRadiation); } public override RemoteControlledCreature CreateAndConfigureRcu(RemoteControlledUnit ammo) diff --git a/src/Perpetuum/Modules/RemoteControl/RemoteControllerModule.cs b/src/Perpetuum/Modules/RemoteControl/RemoteControllerModule.cs index e7faf798..90707289 100644 --- a/src/Perpetuum/Modules/RemoteControl/RemoteControllerModule.cs +++ b/src/Perpetuum/Modules/RemoteControl/RemoteControllerModule.cs @@ -23,13 +23,7 @@ public class RemoteControllerModule : ActiveModule private readonly ModuleProperty bandwidthMax; private readonly ModuleProperty operationalRange; private readonly ModuleProperty lifetime; - private readonly ModuleProperty droneLockingTime; - private readonly ModuleProperty droneArmorMax; - private readonly ModuleProperty droneCoreMax; - private readonly ModuleProperty droneCoreRechargeTime; - private readonly ModuleProperty droneSpeedMax; - private readonly ModuleProperty droneReactorRadiation; - + private BandwidthHandler bandwidthHandler; public double BandwidthMax => bandwidthMax.Value; @@ -51,24 +45,6 @@ public RemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(ammoCatego lifetime = new ModuleProperty(this, AggregateField.remote_control_lifetime); AddProperty(lifetime); - droneLockingTime = new ModuleProperty(this, AggregateField.drone_amplification_locking_time_modifier); - AddProperty(droneLockingTime); - - droneArmorMax = new ModuleProperty(this, AggregateField.drone_amplification_armor_max_modifier); - AddProperty(droneArmorMax); - - droneCoreMax = new ModuleProperty(this, AggregateField.drone_amplification_core_max_modifier); - AddProperty(droneCoreMax); - - droneCoreRechargeTime = new ModuleProperty(this, AggregateField.drone_amplification_core_recharge_time_modifier); - AddProperty(droneCoreRechargeTime); - - droneSpeedMax = new ModuleProperty(this, AggregateField.drone_amplification_speed_max_modifier); - AddProperty(droneSpeedMax); - - droneReactorRadiation = new ModuleProperty(this, AggregateField.drone_amplification_reactor_radiation_modifier); - AddProperty(droneReactorRadiation); - InitBandwidthHandler(this); } @@ -122,7 +98,6 @@ protected override void OnAction() SyncRemoteChannels(); RemoteControlledUnit ammo = GetAmmo() as RemoteControlledUnit; HasFreeBandwidthFor(ammo).ThrowIfFalse(ErrorCodes.MaxBandwidthExceed); - Position targetPosition = GetSpawnPosition(ParentRobot.CurrentPosition); Player player = ParentRobot is Player robotAsPlayer ? robotAsPlayer : null; @@ -144,6 +119,9 @@ protected override void OnAction() UseRemoteChannel(remoteControlledCreature); remoteControlledCreature.DespawnTime = TimeSpan.FromMilliseconds(lifetime.Value); remoteControlledCreature.SetGroup(bandwidthHandler); + Position targetPosition = remoteControlledCreature.IsStationary + ? ParentRobot.CurrentPosition + : GetSpawnPosition(ParentRobot.CurrentPosition); ClosestWalkablePositionFinder finder = new ClosestWalkablePositionFinder(Zone, targetPosition); Position position = finder.FindOrThrow(); remoteControlledCreature.HomePosition = position; diff --git a/src/Perpetuum/Modules/RemoteControl/SupportRemoteControllerModule.cs b/src/Perpetuum/Modules/RemoteControl/SupportRemoteControllerModule.cs index b1c6f4fb..a5bf9f78 100644 --- a/src/Perpetuum/Modules/RemoteControl/SupportRemoteControllerModule.cs +++ b/src/Perpetuum/Modules/RemoteControl/SupportRemoteControllerModule.cs @@ -13,6 +13,13 @@ public class SupportRemoteControllerModule : RemoteControllerModule private readonly ModuleProperty droneRemoteRepairAmount; private readonly ModuleProperty droneRemoteRepairCycleTime; + private readonly ModuleProperty droneLockingTime; + private readonly ModuleProperty droneArmorMax; + private readonly ModuleProperty droneCoreMax; + private readonly ModuleProperty droneCoreRechargeTime; + private readonly ModuleProperty droneSpeedMax; + private readonly ModuleProperty droneReactorRadiation; + public SupportRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryFlags) { droneRemoteRepairAmount = new ModuleProperty(this, AggregateField.drone_amplification_remote_repair_amount_modifier); @@ -20,6 +27,24 @@ public SupportRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(amm droneRemoteRepairCycleTime = new ModuleProperty(this, AggregateField.drone_amplification_remote_repair_cycle_time_modifier); AddProperty(droneRemoteRepairCycleTime); + + droneLockingTime = new ModuleProperty(this, AggregateField.drone_amplification_locking_time_modifier); + AddProperty(droneLockingTime); + + droneArmorMax = new ModuleProperty(this, AggregateField.drone_amplification_armor_max_modifier); + AddProperty(droneArmorMax); + + droneCoreMax = new ModuleProperty(this, AggregateField.drone_amplification_core_max_modifier); + AddProperty(droneCoreMax); + + droneCoreRechargeTime = new ModuleProperty(this, AggregateField.drone_amplification_core_recharge_time_modifier); + AddProperty(droneCoreRechargeTime); + + droneSpeedMax = new ModuleProperty(this, AggregateField.drone_amplification_speed_max_modifier); + AddProperty(droneSpeedMax); + + droneReactorRadiation = new ModuleProperty(this, AggregateField.drone_amplification_reactor_radiation_modifier); + AddProperty(droneReactorRadiation); } public override RemoteControlledCreature CreateAndConfigureRcu(RemoteControlledUnit ammo) diff --git a/src/Perpetuum/Modules/RemoteControl/TacticalRemoteControllerModule.cs b/src/Perpetuum/Modules/RemoteControl/TacticalRemoteControllerModule.cs index 42b6a5fa..79329d72 100644 --- a/src/Perpetuum/Modules/RemoteControl/TacticalRemoteControllerModule.cs +++ b/src/Perpetuum/Modules/RemoteControl/TacticalRemoteControllerModule.cs @@ -15,6 +15,13 @@ public class TacticalRemoteControllerModule : RemoteControllerModule private readonly ModuleProperty droneLongRange; private readonly ModuleProperty droneAccuracy; + private readonly ModuleProperty droneLockingTime; + private readonly ModuleProperty droneArmorMax; + private readonly ModuleProperty droneCoreMax; + private readonly ModuleProperty droneCoreRechargeTime; + private readonly ModuleProperty droneSpeedMax; + private readonly ModuleProperty droneReactorRadiation; + public TacticalRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryFlags) { droneDamage = new ModuleProperty(this, AggregateField.drone_amplification_damage_modifier); @@ -27,6 +34,24 @@ public TacticalRemoteControllerModule(CategoryFlags ammoCategoryFlags) : base(am AddProperty(droneLongRange); droneAccuracy = new ModuleProperty(this, AggregateField.drone_amplification_accuracy_modifier); AddProperty(droneAccuracy); + + droneLockingTime = new ModuleProperty(this, AggregateField.drone_amplification_locking_time_modifier); + AddProperty(droneLockingTime); + + droneArmorMax = new ModuleProperty(this, AggregateField.drone_amplification_armor_max_modifier); + AddProperty(droneArmorMax); + + droneCoreMax = new ModuleProperty(this, AggregateField.drone_amplification_core_max_modifier); + AddProperty(droneCoreMax); + + droneCoreRechargeTime = new ModuleProperty(this, AggregateField.drone_amplification_core_recharge_time_modifier); + AddProperty(droneCoreRechargeTime); + + droneSpeedMax = new ModuleProperty(this, AggregateField.drone_amplification_speed_max_modifier); + AddProperty(droneSpeedMax); + + droneReactorRadiation = new ModuleProperty(this, AggregateField.drone_amplification_reactor_radiation_modifier); + AddProperty(droneReactorRadiation); } public override RemoteControlledCreature CreateAndConfigureRcu(RemoteControlledUnit ammo) diff --git a/src/Perpetuum/Modules/Weapons/MissileWeaponModule.cs b/src/Perpetuum/Modules/Weapons/MissileWeaponModule.cs index c8fdd66e..4bbe36e7 100644 --- a/src/Perpetuum/Modules/Weapons/MissileWeaponModule.cs +++ b/src/Perpetuum/Modules/Weapons/MissileWeaponModule.cs @@ -23,6 +23,7 @@ public MissileWeaponModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryF MissileFalloffModifier = new ModuleProperty(this, AggregateField.module_missile_falloff_modifier); AddProperty(MissileFalloffModifier); propertyExplosionRadius.AddEffectModifier(AggregateField.drone_amplification_accuracy_modifier); + propertyExplosionRadius.AddEffectModifier(AggregateField.turret_amplification_accuracy_modifier); } public override void AcceptVisitor(IEntityVisitor visitor) @@ -40,6 +41,7 @@ public override void UpdateProperty(AggregateField field) case AggregateField.explosion_radius: case AggregateField.explosion_radius_modifier: case AggregateField.drone_amplification_accuracy_modifier: + case AggregateField.turret_amplification_accuracy_modifier: { propertyExplosionRadius.Update(); return; diff --git a/src/Perpetuum/Modules/Weapons/WeaponModule.cs b/src/Perpetuum/Modules/Weapons/WeaponModule.cs index 0bc3de2a..258c36e0 100644 --- a/src/Perpetuum/Modules/Weapons/WeaponModule.cs +++ b/src/Perpetuum/Modules/Weapons/WeaponModule.cs @@ -24,15 +24,19 @@ public WeaponModule(CategoryFlags ammoCategoryFlags) : base(ammoCategoryFlags, t Accuracy = new ModuleProperty(this, AggregateField.accuracy); AddProperty(Accuracy); Accuracy.AddEffectModifier(AggregateField.drone_amplification_accuracy_modifier); + Accuracy.AddEffectModifier(AggregateField.turret_amplification_accuracy_modifier); cycleTime .AddEffectModifier(AggregateField.effect_weapon_cycle_time_modifier); cycleTime .AddEffectModifier(AggregateField.drone_amplification_cycle_time_modifier); + cycleTime + .AddEffectModifier(AggregateField.turret_amplification_cycle_time_modifier); cycleTime .AddEffectModifier(AggregateField.effect_dreadnought_weapon_cycle_time_modifier); DamageModifier = new ModuleProperty(this, AggregateField.damage_modifier); AddProperty(DamageModifier); DamageModifier.AddEffectModifier(AggregateField.drone_amplification_damage_modifier); + DamageModifier.AddEffectModifier(AggregateField.turret_amplification_damage_modifier); DamageModifier.AddEffectModifier(AggregateField.drone_remote_command_translation_damage_modifier); DamageModifier.AddEffectModifier(AggregateField.effect_dreadnought_weapon_damage_modifier); } @@ -50,6 +54,7 @@ public override void UpdateProperty(AggregateField field) switch (field) { case AggregateField.drone_amplification_damage_modifier: + case AggregateField.turret_amplification_damage_modifier: case AggregateField.drone_remote_command_translation_damage_modifier: case AggregateField.effect_dreadnought_weapon_damage_modifier: { @@ -58,6 +63,7 @@ public override void UpdateProperty(AggregateField field) return; } case AggregateField.drone_amplification_accuracy_modifier: + case AggregateField.turret_amplification_accuracy_modifier: { Accuracy.Update(); diff --git a/src/Perpetuum/Units/Unit.cs b/src/Perpetuum/Units/Unit.cs index eb29d4e0..63b0919b 100644 --- a/src/Perpetuum/Units/Unit.cs +++ b/src/Perpetuum/Units/Unit.cs @@ -970,6 +970,7 @@ protected override void OnPropertyChanged(ItemProperty property) break; case AggregateField.drone_amplification_core_recharge_time_modifier: + case AggregateField.turret_amplification_core_recharge_time_modifier: _coreRechargeTime.Update(); break; @@ -1063,6 +1064,7 @@ private void InitUnitProperties() AggregateField.core_recharge_time, AggregateField.core_recharge_time_modifier, AggregateField.drone_amplification_core_recharge_time_modifier, + AggregateField.turret_amplification_core_recharge_time_modifier, AggregateField.effect_core_recharge_time_modifier); AddProperty(_coreRechargeTime); diff --git a/src/Perpetuum/Units/UnitProperties/ArmorMaxProperty.cs b/src/Perpetuum/Units/UnitProperties/ArmorMaxProperty.cs index fea77cc6..fb806c18 100644 --- a/src/Perpetuum/Units/UnitProperties/ArmorMaxProperty.cs +++ b/src/Perpetuum/Units/UnitProperties/ArmorMaxProperty.cs @@ -11,6 +11,7 @@ public ArmorMaxProperty(Unit owner) AggregateField.armor_max_modifier, AggregateField.effect_armor_max_modifier, AggregateField.drone_amplification_armor_max_modifier, + AggregateField.turret_amplification_armor_max_modifier, AggregateField.drone_remote_command_translation_armor_max_modifier) { } diff --git a/src/Perpetuum/Zones/Locking/UnitProperties/LockingTimeProperty.cs b/src/Perpetuum/Zones/Locking/UnitProperties/LockingTimeProperty.cs index bd1e7990..ad466650 100644 --- a/src/Perpetuum/Zones/Locking/UnitProperties/LockingTimeProperty.cs +++ b/src/Perpetuum/Zones/Locking/UnitProperties/LockingTimeProperty.cs @@ -14,7 +14,8 @@ public LockingTimeProperty(Unit owner) AggregateField.effect_sensor_booster_locking_time_modifier, AggregateField.effect_sensor_dampener_locking_time_modifier, AggregateField.effect_locking_time_modifier, - AggregateField.drone_amplification_locking_time_modifier) + AggregateField.drone_amplification_locking_time_modifier, + AggregateField.turret_amplification_locking_time_modifier) { } protected override double CalculateValue() diff --git a/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs b/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs index 511b3958..c47a4634 100644 --- a/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs +++ b/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs @@ -375,7 +375,21 @@ private bool SelectPrimaryTarget() { UnitLock[] validLocks = GetValidLocks(); - return validLocks.Length >= 1 && (stratSelector?.TryUseStrategy(smartCreature, validLocks) ?? false); + if (validLocks.Length < 1) + { + return false; + } + + return TryPriorityStrategy(validLocks) || (stratSelector?.TryUseStrategy(smartCreature, validLocks) ?? false); + } + + // Hook for subclasses that need a target choice to override the weighted strategy + // selection deterministically (e.g. a sentry turret prioritizing its command robot's + // primary-locked target) rather than merely biasing it. Returns false by default, in + // which case the weighted selector runs exactly as before. + protected virtual bool TryPriorityStrategy(UnitLock[] validLocks) + { + return false; } private List FindNewAttackPosition(Unit hostile, CancellationToken cancellationToken) diff --git a/src/Perpetuum/Zones/NpcSystem/AI/SentryTurretCombatAI.cs b/src/Perpetuum/Zones/NpcSystem/AI/SentryTurretCombatAI.cs index f0732091..b6a5de36 100644 --- a/src/Perpetuum/Zones/NpcSystem/AI/SentryTurretCombatAI.cs +++ b/src/Perpetuum/Zones/NpcSystem/AI/SentryTurretCombatAI.cs @@ -1,4 +1,7 @@ -using Perpetuum.Zones.NpcSystem.TargettingStrategies; +using Perpetuum.Zones.Locking.Locks; +using Perpetuum.Zones.NpcSystem.TargettingStrategies; +using Perpetuum.Zones.RemoteControl; +using System; namespace Perpetuum.Zones.NpcSystem.AI { @@ -6,11 +9,30 @@ public class SentryTurretCombatAI : StationaryCombatAI { public SentryTurretCombatAI(SmartCreature smartCreature) : base(smartCreature) { } + public override void Update(TimeSpan time) + { + if ((smartCreature as SentryTurret).IsReceivedRetreatCommand) + { + smartCreature.AI.Push(new SentryTurretRetreatAI(smartCreature)); + + return; + } + + base.Update(time); + } + protected override CombatPrimaryLockSelectionStrategySelector InitSelector() { return CombatPrimaryLockSelectionStrategySelector.Create() .WithStrategy(CombatPrimaryLockSelectionStrategy.HostileOrClosest, 1) .Build(); } + + // The command robot's primary-locked target, when the turret already holds a valid + // lock on it, takes priority over the weighted HostileOrClosest selection above. + protected override bool TryPriorityStrategy(UnitLock[] validLocks) + { + return CombatStrategies.TryInvokeStrategy(CombatPrimaryLockSelectionStrategy.PropagatedPrimary, smartCreature, validLocks); + } } } diff --git a/src/Perpetuum/Zones/NpcSystem/AI/SentryTurretRetreatAI.cs b/src/Perpetuum/Zones/NpcSystem/AI/SentryTurretRetreatAI.cs new file mode 100644 index 00000000..d641bbf9 --- /dev/null +++ b/src/Perpetuum/Zones/NpcSystem/AI/SentryTurretRetreatAI.cs @@ -0,0 +1,34 @@ +using Perpetuum.Zones.RemoteControl; +using System; + +namespace Perpetuum.Zones.NpcSystem.AI +{ + public class SentryTurretRetreatAI : BaseAI + { + public SentryTurretRetreatAI(SmartCreature smartCreature) : base(smartCreature) { } + + public override void Enter() + { + smartCreature.StopAllModules(); + smartCreature.ResetLocks(); + base.Enter(); + } + + public override void Update(TimeSpan time) + { + SentryTurret turret = smartCreature as SentryTurret; + + if (!turret.IsReceivedRetreatCommand) + { + smartCreature.AI.Push(new SentryTurretCombatAI(smartCreature)); + + return; + } + + if (turret.IsInGuardRange) + { + turret.Scoop(); + } + } + } +} diff --git a/src/Perpetuum/Zones/RemoteControl/CombatDrone.cs b/src/Perpetuum/Zones/RemoteControl/CombatDrone.cs index e771d619..c5ee6f18 100644 --- a/src/Perpetuum/Zones/RemoteControl/CombatDrone.cs +++ b/src/Perpetuum/Zones/RemoteControl/CombatDrone.cs @@ -7,14 +7,13 @@ using Perpetuum.Zones.Gates; using Perpetuum.Zones.Locking.Locks; using Perpetuum.Zones.NpcSystem; +using Perpetuum.Zones.NpcSystem.ThreatManaging; using Perpetuum.Zones.Teleporting; namespace Perpetuum.Zones.RemoteControl { public class CombatDrone : RemoteControlledCreature { - public double GuardRange { get; set; } - public override bool IsStationary => false; public CombatDrone(IStandingHandler standingHandler) @@ -42,6 +41,13 @@ public override void OnAggression(Unit victim) CommandRobot.OnAggression(victim); } + // CombatDrone targets exclusively via the command robot's primary lock + // (see IsDetected/HasCommandBotPrimaryLock below) and never reads ThreatManager.Hostiles, + // so body-pull/damage threat is deliberately not tracked here. + public override void AddThreat(Unit hostile, Threat threat, bool spreadToGroup) + { + } + public bool HasCommandBotPrimaryLock() { Lock primary = CommandRobot.GetPrimaryLock(); diff --git a/src/Perpetuum/Zones/RemoteControl/IndustrialDrone.cs b/src/Perpetuum/Zones/RemoteControl/IndustrialDrone.cs index c357fab8..462c365e 100644 --- a/src/Perpetuum/Zones/RemoteControl/IndustrialDrone.cs +++ b/src/Perpetuum/Zones/RemoteControl/IndustrialDrone.cs @@ -21,8 +21,6 @@ public IndustrialDrone(IStandingHandler standingHandler) { } - public double GuardRange { get; set; } - public TurretType TurretType { get; private set; } public override bool IsStationary => false; diff --git a/src/Perpetuum/Zones/RemoteControl/RemoteControlledCreature.cs b/src/Perpetuum/Zones/RemoteControl/RemoteControlledCreature.cs index 9a59d964..fd59f6a7 100644 --- a/src/Perpetuum/Zones/RemoteControl/RemoteControlledCreature.cs +++ b/src/Perpetuum/Zones/RemoteControl/RemoteControlledCreature.cs @@ -6,7 +6,6 @@ using Perpetuum.Services.Standing; using Perpetuum.Units; using Perpetuum.Zones.NpcSystem; -using Perpetuum.Zones.NpcSystem.ThreatManaging; namespace Perpetuum.Zones.RemoteControl { @@ -23,6 +22,8 @@ public class RemoteControlledCreature : SmartCreature public double RemoteChannelBandwidthUsage { get; private set; } + public double GuardRange { get; set; } + public TimeSpan DespawnTime { set => despawnHelper = UnitDespawnHelper.Create(this, value); @@ -62,10 +63,6 @@ public void SetBandwidthUsage(double value) RemoteChannelBandwidthUsage = value; } - public override void AddThreat(Unit hostile, Threat threat, bool spreadToGroup) - { - } - public void Scoop() { RobotInventory cargo = CommandRobot.GetContainer(); diff --git a/src/Perpetuum/Zones/RemoteControl/SentryTurret.cs b/src/Perpetuum/Zones/RemoteControl/SentryTurret.cs index a183503d..323bee58 100644 --- a/src/Perpetuum/Zones/RemoteControl/SentryTurret.cs +++ b/src/Perpetuum/Zones/RemoteControl/SentryTurret.cs @@ -1,9 +1,13 @@ using Perpetuum.EntityFramework; using Perpetuum.Players; +using Perpetuum.Services.RiftSystem; using Perpetuum.Services.Standing; using Perpetuum.Units; +using Perpetuum.Zones.Eggs; +using Perpetuum.Zones.Gates; using Perpetuum.Zones.Locking.Locks; using Perpetuum.Zones.NpcSystem; +using Perpetuum.Zones.Teleporting; using System; namespace Perpetuum.Zones.RemoteControl @@ -15,6 +19,8 @@ public SentryTurret(IStandingHandler standingHandler) { } + public bool IsInGuardRange => CommandRobot.CurrentPosition.IsInRangeOf2D(CurrentPosition, GuardRange); + public override void AcceptVisitor(IEntityVisitor visitor) { if (!TryAcceptVisitor(this, visitor)) @@ -53,6 +59,46 @@ internal override bool IsHostile(SentryTurret turret) return !(turret.CommandRobot is Player player) || IsHostilePlayer(player); } + internal override bool IsHostile(IndustrialDrone drone) + { + return !(drone.CommandRobot is Player player) || IsHostilePlayer(player); + } + + internal override bool IsHostile(SupportDrone drone) + { + return !(drone.CommandRobot is Player player) || IsHostilePlayer(player); + } + + internal override bool IsHostile(Rift rift) + { + return true; + } + + internal override bool IsHostile(Gate gate) + { + return true; + } + + internal override bool IsHostile(AreaBomb bomb) + { + return true; + } + + internal override bool IsHostile(IndustrialTurret turret) + { + return !(turret.CommandRobot is Player player) || IsHostilePlayer(player); + } + + internal override bool IsHostile(Portal portal) + { + return true; + } + + internal override bool IsHostile(MobileTeleport teleport) + { + return true; + } + protected override void UpdateUnitVisibility(Unit target) { if (target is Npc ||