55using ProtoBuf ;
66using Sandbox . Common . ObjectBuilders ;
77using Sandbox . Game ;
8+ using Sandbox . Game . Entities ;
89using Sandbox . Game . EntityComponents ;
910using Sandbox . ModAPI ;
10- using VRage . Game ;
1111using VRage . Game . Components ;
1212using VRage . Game . Entity ;
1313using VRage . Game . ModAPI ;
1616using VRage . Network ;
1717using VRage . ObjectBuilders ;
1818using VRage . Sync ;
19+ using VRage . Utils ;
1920using VRageMath ;
2021using static Draygo . API . HudAPIv2 ;
2122using static VRageRender . MyBillboard ;
22- using Sandbox . Game . Gui ;
23- using Draygo . API ;
23+
2424
2525namespace Starcore . FieldGenerator
2626{
@@ -36,15 +36,24 @@ public class FieldGenerator : MyGameLogicComponent, IMyEventProxy
3636 private int _damageEventCounter = 0 ;
3737 private float _stabilityChange = 0 ;
3838 private int _resetCounter = 0 ;
39- private bool _lowStability = false ;
39+ private bool _lowStability = false ;
40+
41+ internal int _stopTickCounter = - 1 ;
42+ internal Vector3 ? angularAxis1 = null ;
43+ internal Vector3 ? angularAxis2 = null ;
44+
45+ internal bool _cachedState ;
46+ internal MyEntity3DSoundEmitter BlockSoundEmitter ;
47+ internal MySoundPair BlockSoundPair ;
4048
4149 private int initValueDelayTicks = 60 ; // 1 second delay (60 ticks)
4250 private bool valuesInitialized = false ;
4351
4452 #region Sync Properties
4553 public MySync < bool , SyncDirection . BothWays > SiegeMode ;
4654 public MySync < bool , SyncDirection . BothWays > SiegeCooldownActive ;
47- public MySync < bool , SyncDirection . FromServer > GridStopped = null ;
55+ public MySync < bool , SyncDirection . BothWays > SlowdownActive ;
56+ public MySync < bool , SyncDirection . FromServer > GridStopped ;
4857
4958 public MySync < int , SyncDirection . BothWays > SiegeElapsedTime ;
5059 public MySync < int , SyncDirection . BothWays > SiegeCooldownTime ;
@@ -85,6 +94,7 @@ public override void UpdateOnceBeforeFrame()
8594 if ( Block ? . CubeGrid ? . Physics == null )
8695 return ;
8796
97+ BlockSoundEmitter = new MyEntity3DSoundEmitter ( ( MyEntity ) MyAPIGateway . Entities . GetEntityById ( Block . EntityId ) ) ;
8898 FieldGeneratorControls . DoOnce ( ModContext ) ;
8999
90100 Sink = Block . Components . Get < MyResourceSinkComponent > ( ) ;
@@ -130,7 +140,7 @@ public override void UpdateOnceBeforeFrame()
130140
131141 NeedsUpdate |= MyEntityUpdateEnum . EACH_FRAME ;
132142 NeedsUpdate |= MyEntityUpdateEnum . EACH_10TH_FRAME ;
133- }
143+ }
134144
135145 public override void UpdateAfterSimulation ( )
136146 {
@@ -146,11 +156,37 @@ public override void UpdateAfterSimulation()
146156 }
147157 else
148158 {
159+ _cachedState = Block . IsWorking ;
149160 Stability . Value = 100 ;
150161 InitExistingUpgrades ( ) ;
151162 valuesInitialized = true ;
152163 }
153164 }
165+
166+ if ( SiegeMode . Value && ! GridStopped . Value )
167+ {
168+ if ( Block . CubeGrid . Physics . LinearVelocity != Vector3D . Zero )
169+ {
170+ SiegeEmergencyStop ( ) ;
171+ _stopTickCounter ++ ;
172+ }
173+ }
174+ }
175+
176+ if ( SiegeMode . Value && ! GridStopped . Value )
177+ {
178+ if ( ! SlowdownActive . Value )
179+ {
180+ BlockSoundPair = new MySoundPair ( "FieldGen_Brake" ) ;
181+ BlockSoundEmitter ? . PlaySound ( BlockSoundPair , false , false , true , true , false , null , true ) ;
182+ SlowdownActive . Value = true ;
183+ }
184+ }
185+
186+ if ( _cachedState != Block . IsWorking )
187+ {
188+ _cachedState = Block . IsWorking ;
189+ Block_IsWorkingChanged ( ) ;
154190 }
155191
156192 if ( MyAPIGateway . Session . GameplayFrameCounter % 60 == 0 )
@@ -159,7 +195,10 @@ public override void UpdateAfterSimulation()
159195 {
160196 if ( IsServer )
161197 {
162- UpdateSiegeState ( ) ;
198+ if ( GridStopped . Value || SiegeCooldownActive . Value )
199+ {
200+ UpdateSiegeState ( ) ;
201+ }
163202
164203 if ( ! Config . SimplifiedMode )
165204 {
@@ -350,7 +389,7 @@ private void HandleResistence()
350389 return ;
351390 }
352391
353- if ( SiegeMode . Value )
392+ if ( SiegeMode . Value && GridStopped . Value )
354393 {
355394 MyVisualScriptLogicProvider . SetGridGeneralDamageModifier ( Block . CubeGrid . Name , ( 1 - Config . SiegeModeResistence ) ) ;
356395 return ;
@@ -400,6 +439,20 @@ private void OnGridStopValueChange(MySync<bool, SyncDirection.FromServer> obj)
400439 if ( obj ? . Value ?? false )
401440 Block . CubeGrid . Physics . LinearVelocity = Vector3 . Zero ;
402441 }
442+
443+ private void Block_IsWorkingChanged ( )
444+ {
445+ if ( ! Block . IsWorking )
446+ {
447+ BlockSoundPair = Block . IsFunctional ? BlockSoundPair = new MySoundPair ( "FieldGen_Offline" ) : BlockSoundPair = new MySoundPair ( "FieldGen_Damaged" ) ;
448+ BlockSoundEmitter ? . PlaySound ( BlockSoundPair , false , false , true , true , false , null , true ) ;
449+ }
450+ else
451+ {
452+ BlockSoundPair = Block . SlimBlock . IsFullIntegrity ? BlockSoundPair = new MySoundPair ( "FieldGen_PowerRestored" ) : BlockSoundPair = new MySoundPair ( "FieldGen_DamagedRepaired" ) ;
453+ BlockSoundEmitter ? . PlaySound ( BlockSoundPair , false , false , true , true , false , null , true ) ;
454+ }
455+ }
403456 #endregion
404457
405458 #region Siege Mode
@@ -458,12 +511,82 @@ private void SiegeBlockEnabler(IEnumerable<IMyFunctionalBlock> allFunctionalBloc
458511 FieldGeneratorSession . CoreSysAPI . SetFiringAllowed ( entBlock , enabled ) ;
459512 block . Enabled = enabled ;
460513 }
514+ else if ( block is IMyThrust || block is IMyGyro )
515+ {
516+ block . Enabled = enabled ;
517+ }
461518 }
462519 else
463520 continue ;
464521 }
465522 }
466523
524+ private void SiegeEmergencyStop ( )
525+ {
526+ if ( Block . CubeGrid . Physics == null )
527+ return ;
528+
529+ float elapsed = _stopTickCounter / 60f ;
530+ float maxTime = 10f ;
531+
532+ float minForce = 1000000f ;
533+ float maxForce = 120000000f ;
534+
535+ float timeScale = MathHelper . Clamp ( elapsed / maxTime , 0f , 1f ) ;
536+ float forceMagnitude = MathHelper . Lerp ( minForce , maxForce , timeScale ) ;
537+
538+ Vector3 direction = Vector3 . Normalize ( Block . CubeGrid . Physics . LinearVelocity ) ;
539+ Vector3 linearDrag = - direction * forceMagnitude ;
540+
541+ Block . CubeGrid . Physics . AddForce ( MyPhysicsForceType . APPLY_WORLD_FORCE , linearDrag , null , null ) ;
542+
543+ if ( Block . CubeGrid . Physics . LinearVelocity . LengthSquared ( ) < 25f || elapsed >= maxTime ) // 5 m/s squared = 25
544+ {
545+ Block . CubeGrid . Physics . LinearVelocity = Vector3D . Zero ;
546+ GridStopped . Value = true ;
547+ SlowdownActive . Value = false ;
548+ _stopTickCounter = - 1 ;
549+ angularAxis1 = null ;
550+ angularAxis2 = null ;
551+ return ;
552+ }
553+
554+ // ----- ANGULAR DRAG -----
555+ if ( angularAxis1 == null )
556+ {
557+ angularAxis1 = GetRandomUnitVector ( ) ;
558+
559+ Vector3 candidate ;
560+ do
561+ {
562+ candidate = GetRandomUnitVector ( ) ;
563+ }
564+ while ( Math . Abs ( Vector3D . Dot ( candidate , angularAxis1 . Value ) ) > 0.99f ) ;
565+
566+ angularAxis2 = candidate ;
567+ }
568+
569+ float targetAngularAccel = 0.1f ;
570+ Vector3 torqueDirection = new Vector3 ( 0 , 0 , 0 ) ;
571+
572+ torqueDirection += angularAxis1 . Value ;
573+ torqueDirection += angularAxis2 . Value ;
574+
575+ Vector3 angularImpulse = torqueDirection * targetAngularAccel / 60f ;
576+
577+ Block . CubeGrid . Physics . AngularVelocity += angularImpulse ;
578+ }
579+
580+ Vector3 GetRandomUnitVector ( )
581+ {
582+ Vector3 v = new Vector3 (
583+ MyUtils . GetRandomFloat ( - 1f , 1f ) ,
584+ MyUtils . GetRandomFloat ( - 1f , 1f ) ,
585+ MyUtils . GetRandomFloat ( - 1f , 1f )
586+ ) ;
587+ return Vector3 . Normalize ( v ) ;
588+ }
589+
467590 private void EndSiegeMode ( )
468591 {
469592 if ( IsServer && GridStopped . Value )
@@ -606,6 +729,20 @@ public float CalculatePowerDraw()
606729 return Config . MinPowerDraw + t * ( Config . MaxPowerDraw - Config . MinPowerDraw ) ;
607730 }
608731
732+ public float CheckPowerDraw ( float fieldValue )
733+ {
734+ float maxPossibleFieldPowerV = Config . PerModuleAmount * Config . MaxModuleCount ;
735+ float clampedFieldPowerV = MathHelper . Clamp ( fieldValue , 0 , maxPossibleFieldPowerV ) ;
736+ float tV = clampedFieldPowerV / maxPossibleFieldPowerV ;
737+
738+ return Config . MinPowerDraw + tV * ( Config . MaxPowerDraw - Config . MinPowerDraw ) ;
739+ }
740+
741+ public float CheckPowerGeneration ( )
742+ {
743+ return Block . CubeGrid . ResourceDistributor . MaxAvailableResourceByType ( MyResourceDistributorComponent . ElectricityId ) ;
744+ }
745+
609746 private bool IsClientInShip ( )
610747 {
611748 if ( Block != null )
@@ -751,7 +888,11 @@ private void UpdateHUD()
751888 GeneratorHUDContent . Append ( GenerateBar ( "Stability:" , Stability . Value , 100 , true ) ) ;
752889 }
753890
754- if ( SiegeMode . Value )
891+ if ( SiegeMode . Value && ! GridStopped . Value )
892+ {
893+ GeneratorHUDContent . Append ( $ "\n Siege Mode Actived | Emergency Braking Applied") ;
894+ }
895+ else if ( SiegeMode . Value )
755896 {
756897 GeneratorHUDContent . Append ( $ "\n Siege Mode Active | { SiegeElapsedTime . Value } / { Config . MaxSiegeTime } ") ;
757898 }
0 commit comments