Dayz Explorer 1.29.162510
Loading...
Searching...
No Matches
componentenergymanager.c
Go to the documentation of this file.
1//-----------------------------
2// ENERGY MANAGER
3//-----------------------------
4/*
5Author: Boris Vacula
6
7Documentation can be found at DayZ Confluence >> Camping & Squatting >> Electricity >> Energy Manager functionalities
8
9This system controls storage, spending and sharing of energy between instances.
10
11Every EntityAI object which uses this API gains these functions:
12 -It can store some amout of energy
13 -It can use this amount of energy for any kind of functionality
14 -It can share this energy with other devices plugged into it
15 -It will have an ON/OFF switch
16*/
17
19{
20 protected const float DEFAULT_UPDATE_INTERVAL = 15;
21 protected static bool m_DebugPlugs = false; //true; // Use this to toggle visualisation of plug connections
23
24 protected bool m_IsSwichedOn;
25 protected bool m_IsSwichedOnPreviousState; // Necesarry due to synchronization of m_IsSwichedOn
26 protected bool m_IsPassiveDevice;
27 protected bool m_IsWorking;
28 protected bool m_CanWork;
29 protected bool m_CanStopWork;
30 protected bool m_RestorePlugState; // After server restart, this value reports if this device was plugged into something or not at the end of last session.
31 protected bool m_AutoSwitchOff;
33 protected bool m_HasElectricityIcon; // Electricity icon over the item in inventory
35 protected bool m_IsPlugged; // Synchronized variable
37
38 protected int m_MySocketID = -1;
39 protected int m_PlugType;
40 protected int m_EnergySourceStorageIDb1; // Storage persistence ID
41 protected int m_EnergySourceStorageIDb2; // Storage persistence ID
42 protected int m_EnergySourceStorageIDb3; // Storage persistence ID
43 protected int m_EnergySourceStorageIDb4; // Storage persistence ID
45 protected int m_EnergySourceNetworkIDLow = -1; // Network ID
46 protected int m_EnergySourceNetworkIDHigh = -1; // Network ID
47
48 protected float m_EnergyUsage;
49 protected float m_Energy;
50 protected float m_EnergyAtSpawn;
51 protected float m_EnergyStorageMax;
53 protected float m_SocketsCount;
54 protected float m_CordLength;
55 protected float m_LastUpdateTime;
56 protected float m_WetnessExposure;
57 protected float m_UpdateInterval; // Interval of OnWork(...) calls and device updates.
58
59 protected string m_CordTextureFile;
60
61 // Concatenated strings for p3d selections
62 protected static const string SOCKET_ = "socket_";
63 protected static const string _PLUGGED = "_plugged";
64 protected static const string _AVAILABLE = "_available";
65 static const string SEL_CORD_PLUGGED = "cord_plugged";
66 static const string SEL_CORD_FOLDED = "cord_folded";
67
69 EntityAI m_EnergySource; // Energy source can be any EntityAI object
72
76
77 const int MAX_SOCKETS_COUNT = 4;
79
80
81
82 // Constructor
84 {
85 // Disable debug arrows on public release, so that they don't use their timers.
86 #ifndef DEVELOPER
87 m_DebugPlugs = false;
88 #endif
89 }
90
92 {
94 {
95 m_DebugPlugArrow.Destroy();
96 m_DebugPlugArrow = NULL;
97 }
98 }
99
100 // Initialization. Energy Manager is ready.
101 override void Event_OnInit()
102 {
103 if (!m_ThisEntityAI)
104 return;
105
106 m_ThisEntityAI.m_EM = this;
107 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnInitEnergy", NULL, 0);
108 }
109
110 // Update debug arrows
112 {
113 if ( GetDebugPlugs() )
114 {
115 if ( g_Game.IsMultiplayer() && g_Game.IsServer() )
116 {
117 if (m_DebugUpdate)
118 m_DebugUpdate.Stop();
119
120 return;
121 }
122
124 {
125 m_DebugPlugArrow.Destroy();
126 m_DebugPlugArrow = NULL;
127 }
128
130 {
131 vector from = GetEnergySource().GetPosition() + "0 0.1 0";
132 vector to = m_ThisEntityAI.GetPosition() + "0 0.1 0";
133
134 //No need to draw an arrow in this situation as it would not be visible
135 if ( vector.DistanceSq(from, to) == 0 )
136 return;
137
138 if ( m_ThisEntityAI.GetType() == "BarbedWire" ) // Special case for debugging of electric fences. Temporal code until offsets in fences are fixed.
139 {
140 EntityAI BBB = m_ThisEntityAI.GetHierarchyParent();
141
142 if ( BBB && BBB.GetType() == "Fence" )
143 {
144 to = to + "0 -1.3 0";
145 }
146 }
147
148 m_DebugPlugArrow = DrawArrow( from, to );
149 }
150 }
151 }
152
153 Shape DrawArrow(vector from, vector to, float size = 0.5, int color = 0xFFFFFFFF, float flags = 0)
154 {
155 vector dir = to - from;
156 dir.Normalize();
157 vector dir1 = dir * size;
158 size = size * 0.5;
159
160 vector dir2 = dir.Perpend() * size;
161
162 vector pts[5];
163 pts[0] = from;
164 pts[1] = to;
165 pts[2] = to - dir1 - dir2;
166 pts[3] = to - dir1 + dir2;
167 pts[4] = to;
168
169 return Shape.CreateLines(color, flags, pts, 5);
170 }
171
173 {
174 return m_ThisEntityAI;
175 }
176
177 // Prepare everything
178 override void Event_OnAwake()
179 {
180 if (!m_ThisEntityAI)
181 return;
182
183 string cfg_item = "CfgVehicles " + m_ThisEntityAI.GetType();
184 string cfg_energy_manager = cfg_item + " EnergyManager ";
185
186 // Read all config parameters
187 m_EnergyUsage = g_Game.ConfigGetFloat(cfg_energy_manager + "energyUsagePerSecond");
188 bool switch_on = g_Game.ConfigGetFloat(cfg_energy_manager + "switchOnAtSpawn");
189 m_AutoSwitchOff = g_Game.ConfigGetFloat(cfg_energy_manager + "autoSwitchOff");
190 m_HasElectricityIcon = g_Game.ConfigGetFloat(cfg_energy_manager + "hasIcon");
191 m_AutoSwitchOffWhenInCargo = g_Game.ConfigGetFloat(cfg_energy_manager + "autoSwitchOffWhenInCargo");
192
193 m_EnergyAtSpawn = g_Game.ConfigGetFloat(cfg_energy_manager + "energyAtSpawn");
195 m_EnergyStorageMax = g_Game.ConfigGetFloat(cfg_energy_manager + "energyStorageMax");
196 m_ReduceMaxEnergyByDamageCoef = g_Game.ConfigGetFloat(cfg_energy_manager + "reduceMaxEnergyByDamageCoef");
197 m_SocketsCount = g_Game.ConfigGetFloat(cfg_energy_manager + "powerSocketsCount");
198
199 m_IsPassiveDevice = g_Game.ConfigGetFloat(cfg_energy_manager + "isPassiveDevice");
200 m_CordLength = g_Game.ConfigGetFloat(cfg_energy_manager + "cordLength");
201 m_PlugType = g_Game.ConfigGetFloat(cfg_energy_manager + "plugType");
202
203 m_AttachmentActionType = g_Game.ConfigGetFloat(cfg_energy_manager + "attachmentAction");
204 m_WetnessExposure = g_Game.ConfigGetFloat(cfg_energy_manager + "wetnessExposure");
205
206 float update_interval = g_Game.ConfigGetFloat(cfg_energy_manager + "updateInterval");
207
208 m_ConvertEnergyToQuantity = g_Game.ConfigGetFloat(cfg_energy_manager + "convertEnergyToQuantity");
209
210
211 // Check if energy->quantity converion is configured properly
212 float cfg_max_quantity = g_Game.ConfigGetFloat (cfg_item + " varQuantityMax");
213
214 if (m_ConvertEnergyToQuantity && cfg_max_quantity <= 0)
215 {
216 string error = "Error! Item " + m_ThisEntityAI.GetType() + " has invalid configuration of the energy->quantity conversion feature. To fix this, add 'varQuantityMax' parameter with value higher than 0 to the item's config. Then make sure to re-build the PBO containing this item!";
217 Error(error);
219 }
220 else
221 {
223 {
226
227 m_UpdateQuantityTimer.Run( 0.3 , this, "OnEnergyAdded", NULL, false);
228 }
229 }
230
231 // Set update interval
232 if ( update_interval <= 0 )
233 update_interval = DEFAULT_UPDATE_INTERVAL;
234
235 SetUpdateInterval( update_interval );
236
237 // If energyAtSpawn is present, then use its value for energyStorageMax if that cfg param is not present (for convenience's sake)
238 string cfg_check_energy_limit = cfg_energy_manager + "energyStorageMax";
239
240 if ( !g_Game.ConfigIsExisting (cfg_check_energy_limit) && m_Energy > 0 )
241 {
243 }
244
245 // Fill m_CompatiblePlugTypes
246 string cfg_check_plug_types = cfg_energy_manager + "compatiblePlugTypes";
247
248 if ( g_Game.ConfigIsExisting (cfg_check_plug_types) )
249 {
251 g_Game.ConfigGetIntArray(cfg_check_plug_types, m_CompatiblePlugTypes);
252 }
253
254 if (GetSocketsCount() > 0)
256
257 if ( m_CordLength < 0 )
258 {
259 m_CordLength = 0;
260 string error_message_cord = "Warning! " + m_ThisEntityAI.GetType() + ": config parameter 'cordLength' is less than 0! Cord length should not be negative!";
261 DPrint(error_message_cord);
262 }
263
264 if (GetSocketsCount() > 0)
265 {
267 // Prepare the m_DeviceByPlugSelection
268 string cfg_animation_sources = "cfgVehicles " + m_ThisEntityAI.GetType() + " " + "AnimationSources ";
269 int animation_sources_count = g_Game.ConfigGetChildrenCount(cfg_animation_sources);
270
271 for (int i_selection = 0; i_selection < animation_sources_count; i_selection++)
272 {
273 // TO DO: This could be optimized so not all selections on item are considered as plug/socket selections.
274 string selection;
275 g_Game.ConfigGetChildName(cfg_animation_sources, i_selection, selection);
276 m_DeviceByPlugSelection.Set(selection, NULL);
277 }
278 }
279
280
281
282 // Prepare sockets
284 {
286 string error_message_sockets = "Error! " + m_ThisEntityAI.GetType() + ": config parameter 'powerSocketsCount' is higher than the current limit (" + MAX_SOCKETS_COUNT.ToString() + ")! Raise the limit (constant MAX_SOCKETS_COUNT) or decrease the powerSocketsCount parameter for this device!";
287 DPrint(error_message_sockets);
288 }
289
290 m_Sockets[MAX_SOCKETS_COUNT]; // Handles selections for plugs in the sockets. Feel free to change the limit if needed.
291
292 g_Game.ConfigGetText(cfg_energy_manager + "cordTextureFile", m_CordTextureFile);
293
294 if ( switch_on )
295 {
296 SwitchOn();
297 }
298
299 for ( int i = 0; i <= GetSocketsCount(); ++i )
300 {
301 m_ThisEntityAI.HideSelection ( SOCKET_ + i.ToString() + _PLUGGED );
302 }
303
304 // Show/hide inventory sockets
306 if ( GetSocketsCount() > 0 && IsPlugCompatible(PLUG_COMMON_APPLIANCE) && m_ThisEntityAI.GetType() != "MetalWire" ) // metal wire filter is hopefully temporal.
307 {
309 }
310
312
313 m_ThisEntityAI.HideSelection( SEL_CORD_PLUGGED );
314
315
316 #ifdef DIAG_DEVELOPER
317 g_Game.m_EnergyManagerArray.Insert( this );
318 #endif
319 }
320
321 // Returns the type of this component
322 override int GetCompType()
323 {
325 }
326
327 // When the object is deleted
329 {
330 if (!m_ThisEntityAI)
331 return;
332
333 bool was_working = m_ThisEntityAI.GetCompEM().IsWorking();
334
335 SwitchOff();
337 UnplugThis();
338 SetPowered( false );
339
340 if ( was_working )
341 m_ThisEntityAI.OnWorkStop();
342 ;
343 }
344
345 //Restart the debug timer when relogging
347 {
348 if ( m_DebugPlugs )
349 {
350 if ( !m_DebugUpdate )
352
353 if ( !m_DebugUpdate.IsRunning() )
354 m_DebugUpdate.Run(0.01, this, "DebugUpdate", NULL, true);
355 }
356 else
357 {
358 if ( m_DebugPlugArrow )
359 {
360 m_DebugPlugArrow.Destroy();
361 m_DebugPlugArrow = NULL;
362 }
363 }
364 }
365
367 {
368 return m_DebugPlugs;
369 }
370
371 void SetDebugPlugs( bool newVal )
372 {
373 m_DebugPlugs = newVal;
374 RefreshDebug();
375 }
376
377 //======================================================================================
378 // PUBLIC FUNCTIONS
379 // Use these to control the Energy Manager
380 // Functions are in order of their return value: void, bool, int, float, string, array.
381 //======================================================================================
382
384 void SwitchOn()
385 {
387
388 if (g_Game.IsServer() || !g_Game.IsMultiplayer())
389 {
391 {
392 m_IsSwichedOn = true;
393 Synch();
394
395 DeviceUpdate(); // 'Wake up' this device now
396 StartUpdates();
397
398 // 'Wakes up' all connected devices
400
402
403 // Call event
404 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnSwitchOn", NULL, 0);
405 }
406 }
407
408 if ( !g_Game.IsServer() && g_Game.IsMultiplayer()/* && CanSwitchOn() */) // I want the CanSwitchOn() check, but when it's here, the OnSwitchOn() event is never called on client-side due to engine's synchronization system changing the m_IsSwichedOn to true without any specific event beign called. (Yes there is OnVariablesSynchronized() but that is called also when m_CanWork is synchronized, so I need to write a method of knowing when was this specific value changed.)
409 {
410 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnSwitchOn", NULL, 0);
411 }
412 }
413
416 {
418
419 if (g_Game.IsServer() || !g_Game.IsMultiplayer())
420 {
422 {
423 m_IsSwichedOn = false;
424 Synch();
425
426 if (IsWorking())
427 {
428 StopUpdates();
429 DeviceUpdate();
430 }
431
432 // 'Wakes up' all connected devices
434
436
437 // Call event
438 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnSwitchOff", NULL, 0);
439 }
440 }
441
442 if ( !g_Game.IsServer() && g_Game.IsMultiplayer() )
443 {
444 m_IsSwichedOn = false;
445 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnSwitchOff", NULL, 0);
446 }
447 }
448
450 void SetPassiveState(bool state = true)
451 {
452 m_IsPassiveDevice = state;
453 if ( !m_IsPassiveDevice )
454 {
455 DeviceUpdate();
456 }
457 }
458
460 void UnplugDevice(EntityAI device_to_unplug)
461 {
462 if (g_Game)
463 {
464 int indexStart = GetPluggedDevicesCount() - 1;
465 bool deviceFound = false;
466
467 for (int i = indexStart; i >= 0; --i)
468 {
469 EntityAI plugged_device = GetPluggedDevices().Get(i);
470
471 if (plugged_device == device_to_unplug)
472 {
473 GetPluggedDevices().Remove(i);
474 deviceFound = true;
475 break;
476 }
477 }
478
479 if (deviceFound && m_ThisEntityAI)
480 {
481 int socket_ID = device_to_unplug.GetCompEM().GetMySocketID();
482 UnplugCordFromSocket(socket_ID);
483 device_to_unplug.GetCompEM().SetEnergySource(null);
484 device_to_unplug.GetCompEM().DeviceUpdate();
485 device_to_unplug.GetCompEM().StartUpdates();
486 device_to_unplug.GetCompEM().WakeUpWholeBranch(m_ThisEntityAI);
487
489 {
490 m_DebugPlugArrow.Destroy();
491 m_DebugPlugArrow = null;
492 }
493
494 OnOwnSocketReleased(device_to_unplug);
495 device_to_unplug.GetCompEM().OnIsUnplugged(m_ThisEntityAI);
496 device_to_unplug.ShowSelection(SEL_CORD_FOLDED);
497 device_to_unplug.HideSelection(SEL_CORD_PLUGGED);
498 }
499 }
500 }
501
504 {
505 if (g_Game)
506 {
508 {
509 GetEnergySource().GetCompEM().UnplugDevice(m_ThisEntityAI);
510 }
511 }
512 }
513
516 {
517 if ( GetPluggedDevices() ) // This check is necesarry in case this function is called before initialization
518 {
519 int indexStart = GetPluggedDevicesCount() - 1;
520 for (int i = indexStart; i >= 0; --i)
521 {
523 }
524 }
525 }
526
527 // Used only for storing of the plug's state through server restart
528 void RestorePlugState(bool state)
529 {
530 m_RestorePlugState = state;
531 }
532
534 void SetEnergy(float new_energy)
535 {
536 if (m_ThisEntityAI && (g_Game.IsServer() || !g_Game.IsMultiplayer())) // Client can't change energy value.
537 {
538 m_ThisEntityAI.SetWeightDirty();
539 float old_energy = m_Energy;
540 m_Energy = new_energy;
541
542 if (old_energy - GetEnergyUsage() <= 0 || (old_energy != new_energy && Math.Min(old_energy,new_energy) <= 0))
543 {
545 }
546 }
547 }
548
550 void SetEnergy0To1(float energy01)
551 {
552 SetEnergy( Math.Lerp(0, GetEnergyMax(),energy01));
553 }
554
557 {
558 if (!m_ThisEntityAI)
559 return;
560
561 // Lets update sockets, if there are any
562 int slots_c = GetSocketsCount();
563
564 for (int i = 0; i < slots_c; ++i)
565 {
566 EntityAI plug_owner = GetDeviceBySocketID(i);
567
568 if (plug_owner)
569 {
570 string plugged_selection = SOCKET_ + (i+1).ToString() + _PLUGGED;
571 string available_selection = SOCKET_ + (i+1).ToString() + _AVAILABLE;
572 m_ThisEntityAI.ShowSelection(plugged_selection);
573 m_ThisEntityAI.HideSelection(available_selection);
574 string texture_path = plug_owner.GetCompEM().GetCordTextureFile();
575 int selection_index = m_ThisEntityAI.GetHiddenSelectionIndex(plugged_selection);
576 m_ThisEntityAI.SetObjectTexture(selection_index, texture_path);
577 }
578 else
579 {
580 m_ThisEntityAI.ShowSelection(SOCKET_ + (i+1).ToString() + _AVAILABLE);
581 m_ThisEntityAI.HideSelection(SOCKET_ + (i+1).ToString() + _PLUGGED);
582 }
583 }
584
585 // Now lets update the cord/plug state
586 if (GetEnergySource())
587 {
588 m_ThisEntityAI.ShowSelection(SEL_CORD_PLUGGED);
589 m_ThisEntityAI.HideSelection(SEL_CORD_FOLDED);
590 }
591 else
592 {
593 m_ThisEntityAI.ShowSelection(SEL_CORD_FOLDED);
594 m_ThisEntityAI.HideSelection(SEL_CORD_PLUGGED);
595 }
596 }
597
600 {
601 if (m_ThisEntityAI && m_ThisEntityAI.GetCompEM().GetEnergySource())
602 {
603 EntityAI player = m_ThisEntityAI.GetHierarchyRootPlayer();
604 // Check if the item is held in hands during advanced placement
605 if (player)
606 {
607 // Measure distance from the player
608 vector playerPosition = player.GetPosition();
609 if (!IsEnergySourceAtReach(playerPosition, 5))
610 UnplugThis();
611 }
612 else
613 {
614 // Measure distance from the device
615 vector itemPosition = m_ThisEntityAI.GetPosition();
616
617 if (m_ThisEntityAI.GetHierarchyParent())
618 itemPosition = m_ThisEntityAI.GetHierarchyParent().GetPosition();
619
620 if (!IsEnergySourceAtReach(itemPosition))
621 UnplugThis();
622 }
623 }
624 }
625
626 // Returns an array of plug types this device can accept
628 {
630 }
631
632 // Stores IDs of the energy source.
633 void StoreEnergySourceIDs(int b1, int b2, int b3, int b4)
634 {
639 }
640
642 void SetEnergyMaxPristine(float new_limit)
643 {
644 m_EnergyStorageMax = new_limit;
645 }
646
648 void SetCordLength( float new_length )
649 {
650 m_CordLength = new_length;
651 }
652
653 // Sets the plug type (for plug -> socket compatibility checks).
654 void SetPlugType( int new_type )
655 {
656 m_PlugType = new_type;
657 }
658
659 // Sets the new attachment action type.
660 void SetAttachmentAction( int new_action_type )
661 {
662 m_AttachmentActionType = new_action_type;
663 }
664
666 void SetEnergyUsage( float new_usage )
667 {
668 m_EnergyUsage = new_usage;
669 }
670
673 {
674 if (!m_ThisEntityAI)
675 return;
676
677 string cfg_energy_usage = "CfgVehicles " + m_ThisEntityAI.GetType() + " EnergyManager ";
678 m_EnergyUsage = g_Game.ConfigGetFloat (cfg_energy_usage + "energyUsagePerSecond");
679 }
680
681 // Sets path to the cord texture file.
682 void SetCordTextureFile( string new_path )
683 {
684 m_CordTextureFile = new_path;
685 }
686
687 // Sets energy source. Intended to be called only on client through RPC.
689 {
690 SetEnergySource(source);
691 }
692
694 void SetDeviceBySocketID(int id, EntityAI plugged_device)
695 {
696 m_Sockets[id] = plugged_device;
697 }
698
699
701 void SetElectricityIconVisibility( bool make_visible )
702 {
703 m_HasElectricityIcon = make_visible;
704 }
705
706 // Checks whenever this device can work or not and updates this information on all clients. Can be called many times per frame because synchronization happens only once if a change has occured.
708 {
709 if (g_Game.IsServer() || !g_Game.IsMultiplayer())
710 {
711 bool current_state = CanWork();
712 if (current_state != m_CanWork)
713 {
714 m_CanWork = current_state;
715
716 if (m_ThisEntityAI)
717 {
718 Synch();
719 if (m_ThisEntityAI.GetHierarchyParent() && m_ThisEntityAI.GetHierarchyParent().GetCompEM())
720 {
721 m_ThisEntityAI.GetHierarchyParent().GetCompEM().UpdateCanWork();
722 }
723 }
724 }
725 }
726 }
727
729 {
731 {
732 if (IsSwitchedOn())
733 {
734 SwitchOff();
735 }
736 }
737 }
738
740 void SetUpdateInterval( float value )
741 {
742 m_UpdateInterval = value;
743 }
744
745 // Returns true if this device was plugged into something at the end of previous session
747 {
748 return m_RestorePlugState;
749 }
750
752 bool PlugThisInto(EntityAI energy_source, int socket_id = -1)
753 {
754 if (m_ThisEntityAI)
755 {
756 return energy_source.GetCompEM().PlugInDevice(m_ThisEntityAI, socket_id);
757 }
758 else
759 {
760 return false;
761 }
762 }
763
766 {
767 if ( !IsSwitchedOn() )
768 {
769 return true;
770 }
771
772 return false;
773 }
774
775
781 bool CanWork( float test_energy = -1)
782 {
783 if ( g_Game.IsMultiplayer() && g_Game.IsClient() )
784 {
785 return m_CanWork;
786 }
787
788 if (!m_ThisEntityAI || m_ThisEntityAI.IsRuined())
789 {
790 return false;
791 }
792
793 // Check if the power source(s) (which can be serially connected) can provide needed energy.
794 float energy_usage = test_energy;
795 float gathered_energy = GetEnergy();
796 EntityAI energy_source = GetEnergySource();
797
798 if (energy_usage == -1)
799 {
800 energy_usage = GetEnergyUsage();
801 }
802
803 if ( !CheckWetness() )
804 {
805 return false;
806 }
807
808 if (gathered_energy <= 0 && energy_usage <= 0) //empty power source
809 {
810 return false;
811 }
812
813 int cycle_limit = 500; // Sanity check to definitely avoid infinite cycles
814
815 while ( gathered_energy < energy_usage ) // Look for energy source if we don't have enough stored energy
816 {
817 // Safetycheck!
818 if (cycle_limit > 0)
819 {
820 cycle_limit--;
821 }
822 else
823 {
824 DPrint("Energy Manager ERROR: The 'cycle_limit' safety break had to be activated to prevent possible game freeze. Dumping debug information...");
825 //Print(m_ThisEntityAI);
826 //Print(this);
827 //Print(energy_source);
828
829 if (energy_source.GetCompEM())
830 {
831 //Print(energy_source.GetCompEM());
832 }
833
834 //Print(gathered_energy);
835 //Print(energy_usage);
836
837 //Print(m_ThisEntityAI.GetPosition());
838
839 if (energy_source)
840 {
841 //Print(energy_source.GetPosition());
842 }
843
844 //Print("End of the 'cycle_limit' safety break ^ ");
845
846 return false;
847 }
848 // ^ Safetycheck!
849
850 if ( energy_source && energy_source != m_ThisEntityAI && !energy_source.IsRuined() && energy_source.GetCompEM() && energy_source.GetCompEM().IsSwitchedOn() && energy_source.GetCompEM().CheckWetness() )
851 {
852 gathered_energy = gathered_energy + energy_source.GetCompEM().GetEnergy();
853 energy_source = energy_source.GetCompEM().GetEnergySource();
854 }
855 else
856 {
857 // No power source, no energy.
858 return false;
859 }
860 }
861
862 // Enough energy was found
863 return true;
864 }
865
868 {
869 if (m_ThisEntityAI)
870 {
871 return (m_ThisEntityAI.GetWet() <= 1-m_WetnessExposure);
872 }
873 else
874 {
875 return false;
876 }
877 }
878
881 {
882 if ( IsPassive() )
883 {
884 return false;
885 }
886
887 return IsSwitchedOn();
888 }
889
890 // Returns previous state of the switch.
895
898 {
899 return m_IsSwichedOn;
900 }
901
904 {
905 if ( IsPlugged() )
906 return false;
907
908 return true;
909 }
910
913 {
914 return m_IsPassiveDevice;
915 }
916
919 {
920 return m_IsPlugged;
921 }
922
923
925 bool ConsumeEnergy(float amount)
926 {
927 if (m_ThisEntityAI)
928 {
929 return FindAndConsumeEnergy(m_ThisEntityAI, amount, true);
930 }
931 else
932 {
933 return false;
934 }
935 }
936
939 {
940 return m_IsWorking;
941 }
942
945 {
946 if ( GetEnergy() > GetEnergyUsage() )
947 {
948 return true;
949 }
950
951 return false;
952 }
953
955 bool HasFreeSocket( int socket_id = -1 )
956 {
957 if (socket_id == -1)
958 {
959 int plugged_devices = GetPluggedDevicesCount();
960 int plugged_devices_limit = GetSocketsCount();
961
962 if ( plugged_devices < plugged_devices_limit )
963 {
964 return true;
965 }
966
967 return false;
968 }
969 else
970 {
971 EntityAI device = GetDeviceBySocketID(socket_id);
972
973 if (device)
974 {
975 return false;
976 }
977 else
978 {
979 return true;
980 }
981 }
982 }
983
985 bool IsPlugCompatible(int plug_ID)
986 {
987 if ( plug_ID == PLUG_UNDEFINED )
988 {
989 return true; // When plugType is undefined in config then make it compatible.
990 }
991
993 {
994 int nCompatiblePlugTypes = m_CompatiblePlugTypes.Count();
995 for ( int i = 0; i < nCompatiblePlugTypes; ++i )
996 {
997 int plug_ID_to_Check = m_CompatiblePlugTypes.Get(i);
998
999 if ( plug_ID_to_Check == plug_ID )
1000 {
1001 return true;
1002 }
1003 }
1004 }
1005 else
1006 {
1007 // Since the config parameter compatiblePlugTypes is not present, then accept all plugs for simplicity's sake
1008 return true;
1009 }
1010
1011 return false;
1012 }
1013
1015 bool CanReceivePlugFrom( EntityAI device_to_plug )
1016 {
1017 // The following conditions are broken down for the sake of easier reading/debugging.
1018 if (m_ThisEntityAI && HasFreeSocket() && device_to_plug != m_ThisEntityAI)
1019 {
1020 if ( device_to_plug.GetCompEM().GetEnergySource() != m_ThisEntityAI)
1021 {
1022 if ( IsPlugCompatible(device_to_plug.GetCompEM().GetPlugType()) )
1023 {
1024 if ( device_to_plug.GetCompEM().IsEnergySourceAtReach( device_to_plug.GetPosition(), 0, m_ThisEntityAI.GetPosition() ) )
1025 {
1026 return true;
1027 }
1028 }
1029 }
1030 }
1031
1032 return false;
1033 }
1034
1036 bool CanBePluggedInto( EntityAI potential_energy_provider )
1037 {
1038 if (m_ThisEntityAI)
1039 {
1040 return potential_energy_provider.GetCompEM().CanReceivePlugFrom(m_ThisEntityAI);
1041 }
1042 else
1043 {
1044 return false;
1045 }
1046 }
1047
1050 {
1051 return m_HasElectricityIcon;
1052 }
1053
1059
1076 bool IsEnergySourceAtReach( vector from_position, float add_tolerance = 0, vector override_source_position = "-1 -1 -1" )
1077 {
1078 if ( !IsPlugged() && override_source_position == "-1 -1 -1" )
1079 {
1080 return false;
1081 }
1082
1083 if ( GetCordLength() == 0 ) // 0 is an exception, which means infinitely long cable.
1084 {
1085 return true;
1086 }
1087
1088 vector source_pos;
1089 float distance;
1090
1091 if ( override_source_position == "-1 -1 -1" )
1092 {
1093 EntityAI energy_source = GetEnergySource();
1094
1095 if (!energy_source)
1096 return false;
1097
1098 source_pos = energy_source.GetPosition();
1099 distance = vector.Distance( from_position, source_pos );
1100 }
1101 else
1102 {
1103 source_pos = override_source_position;
1104 distance = vector.Distance( from_position, source_pos );
1105 }
1106
1107 if (distance > GetCordLength() + add_tolerance)
1108 {
1109 return false;
1110 }
1111 else
1112 {
1113 return true;
1114 }
1115 }
1116
1121
1123 bool IsSelectionAPlug(string selection_to_test )
1124 {
1125 if ( GetPluggedDevices() )
1126 {
1127 int socket_count = GetSocketsCount();
1128
1129 for ( int i = socket_count; i >= 0; --i )
1130 {
1131 string real_selection = SOCKET_ + i.ToString() +_PLUGGED;
1132
1133 if ( selection_to_test == real_selection)
1134 {
1135 return true;
1136 }
1137 }
1138 }
1139
1140 return false;
1141 }
1142
1143
1144
1145
1148 {
1149 return m_SocketsCount;
1150 }
1151
1154 {
1155 return m_PlugType;
1156 }
1157
1158 // Returns the action ID which is supposed to be done upon receiving an attachment
1160 {
1162 }
1163
1164 // Returns persistent ID (block 1) of the energy source
1169
1170 // Returns persistent ID (block 2) of the energy source
1175
1176 // Returns persistent ID (block 3) of the energy source
1181
1182 // Returns persistent ID (block 4) of the energy source
1187
1188 // Returns network ID (low) of the energy source
1193
1194 // Returns network ID (high) of the energy source
1199
1202 {
1203 if ( GetPluggedDevices() )
1204 {
1205 return GetPluggedDevices().Count();
1206 }
1207
1208 return 0;
1209 }
1210
1213 {
1214 if ( m_EnergyStorageMax > 0 )
1215 {
1216 int coef = Math.Round( m_Energy / m_EnergyStorageMax * 100 );
1217 return coef;
1218 }
1219
1220 return 0;
1221 }
1222
1225 {
1226 if ( m_EnergyStorageMax > 0 )
1227 {
1229 }
1230
1231 return 0;
1232 }
1233
1236 {
1237 #ifdef DIAG_DEVELOPER
1238 if (FeatureTimeAccel.GetFeatureTimeAccelEnabled(ETimeAccelCategories.ENERGY_CONSUMPTION) || (FeatureTimeAccel.GetFeatureTimeAccelEnabled(ETimeAccelCategories.ENERGY_RECHARGE)))
1239 {
1240 return 1;//when modifying time accel, we might want to see things happen when they should, instead of waiting for the next tick
1241 }
1242 #endif
1243 return m_UpdateInterval;
1244 }
1245
1248 {
1249 return m_WetnessExposure;
1250 }
1251
1254 {
1255 return m_EnergyUsage;
1256 }
1257
1260 {
1261 return m_Energy;
1262 }
1263
1265 float AddEnergy(float added_energy)
1266 {
1267 if (added_energy != 0)
1268 {
1269 //Print("AddEnergy ---------> " + added_energy + " " + this + " " +m_ThisEntityAI.ClassName());
1270 #ifdef DIAG_DEVELOPER
1271 if (FeatureTimeAccel.GetFeatureTimeAccelEnabled(ETimeAccelCategories.ENERGY_CONSUMPTION) && added_energy < 0)
1272 {
1273 float timeAccel = FeatureTimeAccel.GetFeatureTimeAccelValue();
1274 added_energy *= timeAccel;
1275 }
1276 #endif
1277
1278 bool energy_was_added = (added_energy > 0);
1279
1280 float energy_to_clamp = GetEnergy() + added_energy;
1281 float clamped_energy = Math.Clamp( energy_to_clamp, 0, GetEnergyMax() );
1282 SetEnergy(clamped_energy);
1283 StartUpdates();
1284
1285 if (energy_was_added)
1286 OnEnergyAdded();
1287 else
1289
1290 return energy_to_clamp - clamped_energy;
1291 }
1292
1293 return 0;
1294 }
1295
1298 {
1299 float max_health = 0;
1300
1301 if (m_ThisEntityAI && m_ThisEntityAI.HasDamageSystem())
1302 max_health = m_ThisEntityAI.GetMaxHealth("","");
1303 //else if ( m_ReduceMaxEnergyByDamageCoef != 0 )
1304 // Error("[ERROR] ReduceMaxEnergyByDamageCoef is setup but " + m_ThisEntityAI.GetType() + " does not have a Damage System");
1305
1306 if ( max_health == 0 || m_ReduceMaxEnergyByDamageCoef == 0 )
1307 return GetEnergyMaxPristine();
1308
1309 float health = 100;
1310
1311 if (m_ThisEntityAI && (g_Game.IsServer() || !g_Game.IsMultiplayer())) // TO DO: Remove this IF when method GetHealth can be called on client!
1312 health = m_ThisEntityAI.GetHealth("","");
1313
1314 float damage_coef = 1 - (health / max_health);
1315
1316 return GetEnergyMaxPristine() * (1 - ( damage_coef * m_ReduceMaxEnergyByDamageCoef ) );
1317 }
1318
1321 {
1322 return m_EnergyStorageMax;
1323 }
1324
1326 {
1327 return m_EnergyAtSpawn;
1328 }
1329
1332 {
1333 return m_CordLength;
1334 }
1335
1338 {
1339 return m_EnergySource;
1340 }
1341
1344 {
1345 return m_Sockets[id];
1346 }
1347
1349 EntityAI GetPlugOwner(string plug_selection_name)
1350 {
1351 if ( m_DeviceByPlugSelection && m_DeviceByPlugSelection.Contains(plug_selection_name) )
1352 {
1353 return m_DeviceByPlugSelection.Get(plug_selection_name);
1354 }
1355
1356 return NULL;
1357 }
1358
1361 {
1362 if ( GetPluggedDevicesCount() > 0 )
1363 {
1364 return GetPluggedDevices().Get(0);
1365 }
1366
1367 return NULL;
1368 }
1369
1372 {
1373 return m_CordTextureFile;
1374 }
1375
1381
1384 {
1385 array<EntityAI> return_array = new array<EntityAI>;
1386 int plugged_devices_c = GetPluggedDevicesCount();
1387 for ( int i = 0; i < plugged_devices_c; ++i )
1388 {
1389 EntityAI device = GetPluggedDevices().Get(i);
1390 if ( IsSwitchedOn() )
1391 {
1392 return_array.Insert(device);
1393 }
1394 }
1395
1396 return return_array;
1397 }
1398
1399
1400 /*===================================
1401 PUBLIC EVENTS
1402 ===================================*/
1403
1404 // Called every device update if its supposed to do some work. The update can be every second or at random, depending on its manipulation.
1405 void OnWork( float consumed_energy )
1406 {
1407 if (m_ThisEntityAI)
1408 m_ThisEntityAI.OnWork(consumed_energy);
1409 }
1410
1411 // Called when this device is plugged into some energy source
1412 void OnIsPlugged(EntityAI source_device)
1413 {
1414 if (m_DebugPlugs)
1415 {
1416 if (!m_DebugUpdate)
1418
1419 if (!m_DebugUpdate.IsRunning())
1420 m_DebugUpdate.Run(0.01, this, "DebugUpdate", NULL, true);
1421 }
1422
1423 UpdateCanWork();
1424 if (m_ThisEntityAI)
1425 m_ThisEntityAI.OnIsPlugged(source_device);
1426 }
1427
1428 // Called when this device is UNPLUGGED from the energy source
1429 void OnIsUnplugged( EntityAI last_energy_source )
1430 {
1431 UpdateCanWork();
1432 if (m_ThisEntityAI)
1433 m_ThisEntityAI.OnIsUnplugged( last_energy_source );
1434 }
1435
1436 // When something is plugged into this device
1438 {
1439 if (!m_ThisEntityAI)
1440 return;
1441
1442 //play sound
1443 if (device.GetCompEM().GetPlugType() == PLUG_COMMON_APPLIANCE && m_ThisEntityAI.IsInitialized())
1444 {
1445 EffectSound sound_plug;
1446 m_ThisEntityAI.PlaySoundSet(sound_plug, "cablereel_plugin_SoundSet", 0, 0);
1447 }
1448
1449 m_ThisEntityAI.OnOwnSocketTaken(device);
1450 }
1451
1452 // When something is UNPLUGGED from this device
1454 {
1455 if (!m_ThisEntityAI)
1456 return;
1457
1458 //play sound
1459 if ( device.GetCompEM().GetPlugType() == PLUG_COMMON_APPLIANCE && m_ThisEntityAI.IsInitialized() )
1460 {
1461 EffectSound sound_unplug;
1462 m_ThisEntityAI.PlaySoundSet( sound_unplug, "cablereel_unplug_SoundSet", 0, 0 );
1463 }
1464
1465 m_ThisEntityAI.OnOwnSocketReleased( device );
1466 }
1467
1468
1469 // Handles automatic attachment action
1470 void OnAttachmentAdded(EntityAI elec_device)
1471 {
1472 if (!m_ThisEntityAI)
1473 return;
1474
1475 int attachment_action_type = GetAttachmentAction();
1476
1477 if (attachment_action_type == PLUG_THIS_INTO_ATTACHMENT)
1478 {
1479 if (elec_device.GetCompEM().CanReceivePlugFrom(m_ThisEntityAI))
1480 {
1481 PlugThisInto(elec_device);
1482 }
1483 }
1484 else if (attachment_action_type == PLUG_ATTACHMENTS_INTO_THIS)
1485 {
1486 elec_device.GetCompEM().PlugThisInto(m_ThisEntityAI);
1487 }
1488 }
1489
1490 // Handles automatic detachment action
1492 {
1493 int attachment_action_type = GetAttachmentAction();
1494
1495 if ( attachment_action_type == PLUG_THIS_INTO_ATTACHMENT )
1496 {
1497 if ( elec_device == GetEnergySource() )
1498 {
1499 UnplugThis();
1500 }
1501 }
1502 else if ( attachment_action_type == PLUG_ATTACHMENTS_INTO_THIS )
1503 {
1504 elec_device.GetCompEM().UnplugThis();
1505 }
1506 }
1507
1508 // Starts the device's main cycle
1510 {
1511 if (!m_IsPassiveDevice)
1512 {
1513 if (!m_UpdateTimer)
1515
1516 if (!m_UpdateTimer.IsRunning()) // Makes sure the timer is NOT running already
1517 {
1518 m_UpdateTimer.Run(GetUpdateInterval(), this, "DeviceUpdate", null, true);
1519 }
1520 }
1521 }
1522
1525 {
1526 if (m_ThisEntityAI)
1527 m_ThisEntityAI.OnEnergyConsumed();
1528 }
1529
1532 {
1534 {
1535 m_UpdateQuantityTimer.Stop();
1536 m_UpdateQuantityTimer = NULL;
1537 }
1538
1539 if (m_ThisEntityAI)
1540 m_ThisEntityAI.OnEnergyAdded();
1541 }
1542
1543
1544 /*===================================
1545 PROTECTED FUNCTIONS
1546 ===================================*/
1547
1548 // Stops the device's main cycle
1549 protected void StopUpdates()
1550 {
1551 if (m_UpdateTimer)
1552 {
1553 m_UpdateTimer.Stop();
1554 m_UpdateTimer = NULL; // Delete timer from memory
1555 }
1556 }
1557
1561 void InteractBranch(EntityAI originalCaller, Man player = null, int system = 0)
1562 {
1563 OnInteractBranch(originalCaller, player, system);
1564 if ( GetSocketsCount() > 0 )
1565 {
1567
1568 foreach ( EntityAI device : devices)
1569 {
1570 if ( device != originalCaller ) // originalCaller check here prevents infinite loops
1571 {
1572 device.GetCompEM().InteractBranch( originalCaller, player, system );
1573 }
1574 }
1575 }
1576 }
1577
1579 protected void OnInteractBranch(EntityAI originalCaller, Man player, int system)
1580 {
1581 if (m_ThisEntityAI)
1582 m_ThisEntityAI.IncreaseLifetime();
1583
1584 }
1585
1586 // 'Wakes up' all devices down the network so they start working, if they have enough power, and are switched ON
1587 protected void WakeUpWholeBranch( EntityAI original_caller )
1588 {
1589 if ( GetSocketsCount() > 0 )
1590 {
1591 array<EntityAI> plugged_devices = GetPluggedDevices();
1592 int plugged_devices_c = plugged_devices.Count();
1593
1594 for ( int i = 0; i < plugged_devices_c; ++i )
1595 {
1596 EntityAI device = plugged_devices.Get(i);
1597 if ( device != original_caller ) // original_caller check here prevents infinite loops
1598 {
1599 device.GetCompEM().UpdateCanWork();
1600 device.GetCompEM().DeviceUpdate();
1601 device.GetCompEM().StartUpdates();
1602 device.GetCompEM().WakeUpWholeBranch( original_caller );
1603 }
1604 }
1605 }
1606 }
1607
1608 // Finds an available socket and plugs the given device into it.
1609 // This is mainly about visualisation.
1610 protected void PlugCordIntoSocket( EntityAI device_to_plug, int socket_id = -1 )
1611 {
1612 if (socket_id >= 0)
1613 {
1614 EntityAI plug_owner_by_socket = GetDeviceBySocketID(socket_id);
1615
1616 if (!plug_owner_by_socket)
1617 {
1618 UpdateSocketSelections(socket_id, device_to_plug);
1619 return;
1620 }
1621 }
1622
1623 int slots_c = GetSocketsCount();
1624
1625 for ( int i = 0; i < slots_c; ++i )
1626 {
1627 EntityAI plug_owner = GetDeviceBySocketID(i);
1628
1629 if ( !plug_owner ) // Check if this socket is available
1630 {
1631 UpdateSocketSelections(i, device_to_plug);
1632 break;
1633 }
1634 }
1635 }
1636
1637 // Updates socket selections (plugged/unplugged) of the given ID and sets color texture of the plug.
1638 protected void UpdateSocketSelections(int socket_id, EntityAI device_to_plug)
1639 {
1640 if (!m_ThisEntityAI)
1641 return;
1642
1643 SetDeviceBySocketID(socket_id, device_to_plug);
1644
1645 string plugged_selection = SOCKET_ + (socket_id+1).ToString() + _PLUGGED;
1646 SetPlugOwner( plugged_selection, device_to_plug );
1647 m_ThisEntityAI.ShowSelection ( plugged_selection );
1648
1649 string unplugged_selection = SOCKET_ + (socket_id+1).ToString() + _AVAILABLE;
1650 m_ThisEntityAI.HideSelection ( unplugged_selection );
1651 string texture_path = device_to_plug.GetCompEM().GetCordTextureFile();
1652 int selection_index = m_ThisEntityAI.GetHiddenSelectionIndex( plugged_selection );
1653 m_ThisEntityAI.SetObjectTexture( selection_index, texture_path );
1654 device_to_plug.GetCompEM().SetMySocketID(socket_id);
1655 }
1656
1657
1658 // Sets energy source for this device
1659 protected void SetEnergySource( EntityAI source )
1660 {
1661 m_EnergySource = source;
1662
1663 if (source)
1664 {
1665 m_IsPlugged = true;
1666 StartUpdates();
1667 }
1668 else
1669 {
1670 m_IsPlugged = false;
1673 }
1674
1675 if (m_EnergySource)
1677
1678 Synch();
1679 }
1680
1681 // Plugs the given device into this one
1682 protected bool PlugInDevice(EntityAI device_to_plug, int socket_id = -1)
1683 {
1684 if (m_ThisEntityAI && CanReceivePlugFrom(device_to_plug))
1685 {
1686 device_to_plug.IncreaseLifetime();
1688 if (device_to_plug.GetCompEM().IsPlugged())
1689 device_to_plug.GetCompEM().UnplugThis();
1690
1691 GetPluggedDevices().Insert(device_to_plug);
1692 device_to_plug.GetCompEM().SetEnergySource(m_ThisEntityAI);
1693
1694 PlugCordIntoSocket(device_to_plug, socket_id); // Visualisation
1695 OnOwnSocketTaken(device_to_plug);
1696
1697 device_to_plug.GetCompEM().OnIsPlugged(m_ThisEntityAI);
1699
1700 if (g_Game.IsServer() || !g_Game.IsMultiplayer())
1701 {
1702 device_to_plug.HideSelection(SEL_CORD_FOLDED);
1703 device_to_plug.ShowSelection(SEL_CORD_PLUGGED);
1704 }
1705
1706 return true;
1707 }
1708
1709 return false;
1710 }
1711
1712 // Sets the device to which the given plug selection belongs to
1713 protected void SetPlugOwner(string selection_name, EntityAI device)
1714 {
1715 if ( m_DeviceByPlugSelection.Contains(selection_name) )
1716 {
1717 m_DeviceByPlugSelection.Set(selection_name, device);
1718 }
1719 }
1720
1721 // Frees the given socket.
1722 // This is only about visualisation.
1723 protected void UnplugCordFromSocket( int socket_to_unplug_ID )
1724 {
1725 EntityAI plug_owner = GetDeviceBySocketID(socket_to_unplug_ID);
1726
1727 if (m_ThisEntityAI && plug_owner)
1728 {
1729 SetDeviceBySocketID(socket_to_unplug_ID, NULL);
1730 string unplugged_selection = SOCKET_ + (socket_to_unplug_ID+1).ToString() + _AVAILABLE;
1731 m_ThisEntityAI.ShowSelection ( unplugged_selection );
1732
1733 string plugged_selection = SOCKET_ + (socket_to_unplug_ID+1).ToString() + _PLUGGED;
1734 m_ThisEntityAI.HideSelection ( plugged_selection );
1735 SetPlugOwner( plugged_selection, NULL );
1736 plug_owner.GetCompEM().SetMySocketID(-1);
1737 }
1738 }
1739
1740 // Sets the state of the device
1741 protected void SetPowered( bool state )
1742 {
1743 m_IsWorking = state;
1744 }
1745
1746 // Tries to consume the given amount of energy. If there is none in this device, then it tries to take it from some power source.
1747 protected bool FindAndConsumeEnergy(EntityAI original_caller, float amount, bool ignore_switch_state = false)
1748 {
1749 if ((ignore_switch_state || IsSwitchedOn()) && m_ThisEntityAI && !m_ThisEntityAI.IsRuined())
1750 {
1751 float available_energy = AddEnergy(-amount);
1752
1753 if (available_energy < 0 && IsPlugged())
1754 {
1755 // This devices does not has enough of stored energy, therefore it will take it from its power source (which can be a chain of cable reels)
1756 EntityAI next_power_source = GetEnergySource();
1757
1758 if (next_power_source && next_power_source != original_caller) // Prevents infinite loop if the power source is the original caller itself
1759 {
1760 return next_power_source.GetCompEM().FindAndConsumeEnergy(original_caller, -available_energy);
1761 }
1762 }
1763
1764 if (available_energy >= 0)
1765 {
1766 return true;
1767 }
1768
1769 return false;
1770 }
1771 else
1772 {
1773 return false;
1774 }
1775 }
1776
1777 // Gets the socket ID this device is powered from.
1778 protected int GetMySocketID()
1779 {
1780 return m_MySocketID;
1781 }
1782
1783 // Sets the socket ID this device is plugged into.
1784 protected void SetMySocketID( int slot_ID )
1785 {
1786 m_MySocketID = slot_ID;
1787 }
1788
1789 void Synch()
1790 {
1791 if (m_ThisEntityAI && g_Game.IsServer())
1792 m_ThisEntityAI.SetSynchDirty();
1793 }
1794
1796 {
1797 m_LastUpdateTime = 0;
1798 }
1799
1804
1806 {
1807 return g_Game.GetTime();
1808 }
1809
1810 // Updates the device's state of power. This function is visualized in the diagram at DayZ Confluence >> Camping & Squatting >> Electricity >> Energy Manager functionalities
1812 {
1813 /*
1814 vector pos = m_ThisEntityAI.GetPosition();
1815 string debug_message = "Object " + m_ThisEntityAI.GetType() + " | Energy: " + GetEnergy() + " | IsAtReach: " + (IsEnergySourceAtReach(pos)).ToString();
1816 Print(debug_message);
1817 */
1818
1819 if ( !m_IsPassiveDevice )
1820 {
1821 // 'm_ThisEntityAI' and 'this' must be checked because this method is caled from a timer
1822 if (m_ThisEntityAI && this && IsSwitchedOn() && !m_ThisEntityAI.IsRuined() && CheckWetness() && m_CanWork && !g_Game.IsMissionMainMenu())
1823 {
1824 bool was_powered = IsWorking();
1825 float consumed_energy_coef;
1826 // Make sure to use only as much % of energy as needed since this function can be called at random.
1827
1828 if ( m_LastUpdateTime == 0 )
1829 {
1831 consumed_energy_coef = 1.0;
1832 }
1833 else
1834 {
1835 float updatetime = GetCurrentUpdateTime();
1836 float time = updatetime - m_LastUpdateTime;
1837 consumed_energy_coef = time / 1000;
1838 }
1839
1840 if (consumed_energy_coef > 0) // Prevents calling of OnWork events when no energy is consumed
1841 {
1843 float consume_energy = GetEnergyUsage() * consumed_energy_coef;
1844 bool has_consumed_enough = true;
1845
1846 if (g_Game.IsServer() || !g_Game.IsMultiplayer()) // single player or server side multiplayer
1847 has_consumed_enough = ConsumeEnergy( consume_energy );
1848
1849 SetPowered( has_consumed_enough );
1850
1851 if ( has_consumed_enough )
1852 {
1853 if ( !was_powered )
1854 {
1855 m_CanStopWork = true;
1857 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnWorkStart", NULL, 0);
1858 UpdateCanWork();
1859 }
1860
1861 OnWork( consume_energy );
1862 }
1863 else
1864 {
1865 if ( was_powered )
1866 {
1867 if (m_CanStopWork)
1868 {
1869 m_CanStopWork = false;
1871 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnWorkStop", NULL, 0); // This event is called only once when the device STOPS being powered
1872 UpdateCanWork();
1873
1874 if (m_AutoSwitchOff)
1875 {
1876 SwitchOff();
1877 }
1878 }
1879 }
1880
1881 StopUpdates();
1882 }
1883 }
1884 else
1885 {
1887 }
1888 }
1889 else if (this && m_ThisEntityAI)
1890 {
1891 SetPowered( false );
1892 StopUpdates();
1893
1894 if (m_CanStopWork)
1895 {
1896 m_CanStopWork = false;
1898 g_Game.GameScript.CallFunction(m_ThisEntityAI, "OnWorkStop", NULL, 0); // This event is called only once when the device STOPS being powered
1899 UpdateCanWork();
1900
1901 if (m_AutoSwitchOff)
1902 {
1903 SwitchOff();
1904 }
1905 }
1906 }
1907 }
1908 }
1909}
#define PLUG_UNDEFINED
#define PLUG_THIS_INTO_ATTACHMENT
#define PLUG_COMMON_APPLIANCE
#define PLUG_ATTACHMENTS_INTO_THIS
static const string SEL_CORD_FOLDED
void SetElectricityIconVisibility(bool make_visible)
Energy manager: Sets visibility of the electricity icon (bolt).
void SwitchOn()
Energy manager: Switches ON the device so it starts doing its work if it has enough energy.
float GetEnergyMax()
Energy manager: Returns the maximum amount of energy this device can curently store....
void UnplugAllDevices()
Energy manager: Unplugs everything directly connected to this device.
void InteractBranch(EntityAI originalCaller, Man player=null, int system=0)
float GetEnergyUsage()
Energy manager: Returns the number of energy this device needs to run itself (See its config >> energ...
void OnInteractBranch(EntityAI originalCaller, Man player, int system)
Called when the player is interacting with an item containing this energy component,...
bool IsWorking()
Energy manager: Returns true if this device is working right now.
void SetEnergyMaxPristine(float new_limit)
Energy manager: Changes the maximum amount of energy this device can store (when pristine).
Shape DrawArrow(vector from, vector to, float size=0.5, int color=0xFFFFFFFF, float flags=0)
static const string _AVAILABLE
void GetCompatiblePlugTypes(out TIntArray IDs)
void SetEnergy0To1(float energy01)
Energy manager: Sets stored energy for this device between 0 and MAX based on relative input value be...
bool HasFreeSocket(int socket_id=-1)
Energy manager: Returns true if this device has any free socket to receive a plug....
float GetWetnessExposure()
Returns wetness exposure value defined in config.
void WakeUpWholeBranch(EntityAI original_caller)
void UnplugDevice(EntityAI device_to_unplug)
Energy manager: Unplugs the given device from this one.
bool CheckWetness()
Energy manager: Checks if this device is being stopped from working by its wetness level....
void SetUpdateInterval(float value)
Energy manager: Sets the interval of the OnWork(...) calls. Changing this value does not change the r...
void SetPassiveState(bool state=true)
Energy manager: Changes the status of this device. When it's passive (true), the main timer and OnWor...
bool PlugInDevice(EntityAI device_to_plug, int socket_id=-1)
void SetAttachmentAction(int new_action_type)
bool FindAndConsumeEnergy(EntityAI original_caller, float amount, bool ignore_switch_state=false)
void OnEnergyAdded()
Energy manager: Called when energy was added on this device.
void UnplugCordFromSocket(int socket_to_unplug_ID)
float AddEnergy(float added_energy)
Energy manager: Adds energy to this device and clamps it within its min/max storage limits....
void UnplugThis()
Energy manager: Unplugs this device from its power source.
int GetPluggedDevicesCount()
Energy manager: Returns the number of devices plugged into this one.
void SetCordLength(float new_length)
Energy manager: Changes the length of the virtual power cord.
void SetEnergySourceClient(EntityAI source)
void SetEnergySource(EntityAI source)
int GetEnergy0To100()
Energy manager: Returns % of stored energy this device has as integer (from 0 to 100).
void PlugCordIntoSocket(EntityAI device_to_plug, int socket_id=-1)
bool IsEnergySourceAtReach(vector from_position, float add_tolerance=0, vector override_source_position="-1 -1 -1")
Energy manager: Returns true if this device's virtual power cord can reach its energy source at the g...
void HandleMoveInsideCargo(EntityAI container)
float GetEnergy()
Energy manager: Returns the amount of stored energy this device has.
int GetPlugType()
Energy manager: Returns plug type. Check \DZ\data\basicDefines.hpp OR \Scripts\Classes\Component_cons...
bool CanBePluggedInto(EntityAI potential_energy_provider)
Energy manager: Returns true if this device can be plugged into the given energy source....
bool IsPlugged()
Energy manager: Returns true if this device is plugged into some other device (even if they are OFF o...
EntityAI GetEnergySource()
Energy manager: Returns the energy source this device is plugged into.
ref array< EntityAI > m_PluggedDevices
void OnAttachmentRemoved(EntityAI elec_device)
void OnWork(float consumed_energy)
array< EntityAI > GetPluggedDevices()
Energy manager: Returns an array of devices which are plugged into this one.
bool IsPassive()
Energy manager: Returns true if this device is set to be passive. False if otherwise.
bool HasConversionOfEnergyToQuantity()
Energy manager: Returns true if this item automatically converts its energy to quantity.
void StoreEnergySourceIDs(int b1, int b2, int b3, int b4)
void UpdatePlugState()
Energy manager: Unplugs this device when it's necesarry.
void OnAttachmentAdded(EntityAI elec_device)
void OnIsPlugged(EntityAI source_device)
EntityAI m_Sockets[MAX_SOCKETS_COUNT]
string GetCordTextureFile()
Energy manager: Returns path to the cord texture file.
ref map< string, EntityAI > m_DeviceByPlugSelection
bool IsSelectionAPlug(string selection_to_test)
Energy manager: Returns true if this selection is a plug that's plugged into this device....
void SetEnergy(float new_energy)
Energy manager: Sets stored energy for this device. It ignores the min/max limit!
void SetPlugOwner(string selection_name, EntityAI device)
float GetCordLength()
Energy manager: Returns the length of the virtual power cord.
EntityAI GetPlugOwner(string plug_selection_name)
Energy manager: Returns the device to which the given plug selection belongs to.
bool CanWork(float test_energy=-1)
Energy manager: Checks whenever this device can do work or not.
EntityAI GetPluggedDevice()
Energy manager: Returns a device which is plugged into this one. If there are more devices to choose ...
void UpdateSelections()
Energy manager: Shows/Hides all selections this system works with. Call this if something is wrong wi...
void OnIsUnplugged(EntityAI last_energy_source)
static const string SEL_CORD_PLUGGED
bool IsCordFolded()
Energy manager: Returns true if the cord of this device is folded. Returns false if it's plugged.
float GetEnergy0To1()
Energy manager: Returns % of stored energy this device has as float (from 0.0 to 1....
void SwitchOff()
Energy manager: Switches OFF the device.
void OnOwnSocketReleased(EntityAI device)
array< EntityAI > GetPoweredDevices()
Energy manager: Returns an array of devices which are plugged into this one and are turned on.
bool ConsumeEnergy(float amount)
Energy manager: Consumes the given amount of energy. If there is not enough of stored energy in this ...
bool CanSwitchOn()
Energy manager: Checks if the device can be switched ON.
void ResetEnergyUsage()
Energy manager: Resets energy usage to default (config) value.
bool IsPlugCompatible(int plug_ID)
Energy manager: Checks if the given plug is compatible with this device's socket. Used by CanReceiveP...
void SetEnergyUsage(float new_usage)
Energy manager: Changes the energy usage per second.
void OnEnergyConsumed()
Energy manager: Called when energy was consumed on this device.
void SetCordTextureFile(string new_path)
bool CanSwitchOff()
Energy manager: Checks if the device can be switched OFF.
int GetSocketsCount()
Energy manager: Returns the count of power sockets (whenever used or not).
void SetDeviceBySocketID(int id, EntityAI plugged_device)
Energy manager: Stores the device which is plugged into the given socket ID.
void UpdateSocketSelections(int socket_id, EntityAI device_to_plug)
float GetUpdateInterval()
Energy manager: Returns the update interval of this device.
bool HasElectricityIcon()
Energy manager: Returns true if the electricity icon (bolt) is supposed to be visible for this device...
void OnOwnSocketTaken(EntityAI device)
bool PlugThisInto(EntityAI energy_source, int socket_id=-1)
Energy manager: Attempts to plug this device into the energy_source. Returns true if the action was s...
EntityAI GetDeviceBySocketID(int id)
Energy manager: Returns the device which is plugged into the given socket ID.
float GetEnergyMaxPristine()
Energy manager: Returns the maximum amount of energy this device can store. It's damage is NOT taken ...
bool IsSwitchedOn()
Energy manager: Returns state of the switch. Whenever the device is working or not does not matter....
bool HasEnoughStoredEnergy()
Energy manager: Returns true if this device has enough of stored energy for its own use.
bool CanReceivePlugFrom(EntityAI device_to_plug)
Energy manager: Returns true if this device can receive power plug of the other device.
EntityAI m_ThisEntityAI
Definition component.c:24
Wrapper class for managing sound through SEffectManager.
Definition effectsound.c:5
Definition enmath.c:7
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
DayZGame g_Game
Definition dayzgame.c:3942
proto string ToString()
const int COMP_TYPE_ENERGY_MANAGER
Definition component.c:9
void Error(string err)
Messagebox with error message.
Definition endebug.c:90
proto void DPrint(string var)
Prints content of variable to console/log. Should be used for critical messages so it will appear in ...
class DiagMenu Shape
don't call destructor directly. Use Destroy() instead
array< int > TIntArray
Definition enscript.c:714
const int CALL_CATEGORY_SYSTEM
Definition tools.c:8
override float Get()