EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Ship.cpp
Go to the documentation of this file.
1 
2 #include "Client.h"
3 #include "EntityList.h"
4 #include "EVEServerConfig.h"
5 #include "Profiler.h"
6 #include "StaticDataMgr.h"
8 #include "character/Character.h"
10 #include "npc/Drone.h"
11 #include "ship/Ship.h"
13 #include "station/Station.h"
14 #include "system/DestinyManager.h"
15 #include "system/BubbleManager.h"
16 #include "system/SolarSystem.h"
17 #include "system/SystemBubble.h"
18 #include "system/SystemManager.h"
19 
20 /*
21  * ShipItem
22  */
23 ShipItem::ShipItem(uint32 shipID, const ItemType &type, const ItemData &data)
24 : InventoryItem(shipID, type, data),
25 m_pilot(nullptr),
26 m_targetRef(InventoryItemRef(nullptr)),
27 m_ModuleManager(new ModuleManager(this)),
28 m_loaded(false),
29 m_isActive(false),
30 m_isPopped(false),
31 m_isDocking(false),
32 m_isUndocking(false)
33 {
34  m_onlineModuleVec.clear();
36 
37  _log(ITEM__TRACE, "Created ShipItem for %s(%u).", name(), itemID());
38 }
39 
41 {
44 }
45 
47 {
48  return InventoryItem::Load<ShipItem>( shipID);
49 }
50 
52  uint32 shipID(InventoryItem::CreateItemID(data));
53  if (shipID == 0)
54  return ShipItemRef(nullptr);
55 
56  return ShipItem::Load( shipID);
57 }
58 
60  return InventoryItem::CreateItemID(data);
61 }
62 
64 {
65  if (m_loaded and (m_ModuleManager != nullptr))
66  return true;
67 
68  Client* pClient = sItemFactory.GetUsingClient();
69  // test for character creation (which throws errors on following *load() calls and not really needed)
70  if ((pClient != nullptr) and pClient->IsCharCreation())
71  return true;
72  // load attributes
73  if (!InventoryItem::_Load())
74  return false;
75  // load contents
76  if (!pInventory->LoadContents())
77  return false;
78 
80 
81  return (m_loaded = true);
82 }
83 
85 {
87  SaveShip();
88 
89  pInventory->Unload();
90 
91  // remove ship item from factory master list here, as *something* changes ship position when saving from factory.
92  sItemFactory.RemoveItem(m_itemID);
93 
94  // remove ship item from its' container's inventory list also.
95  Inventory* pInv(nullptr);
96  if (sDataMgr.IsStation(locationID())) {
97  pInv = sItemFactory.GetStationItem(locationID())->GetMyInventory();
98  } else {
99  pInv = sItemFactory.GetSolarSystem(locationID())->GetMyInventory();
100  }
101 
102  if (pInv != nullptr)
103  pInv->RemoveItem(ShipItemRef(this));
104 }
105 
106 void ShipItem::SetPlayer(Client* pClient) {
107  if (m_pilot == pClient)
108  return;
109  if (pClient == nullptr) {
111  if (m_pilot != nullptr)
113  // remove ship effects and char skill effects for char leaving ship.
114  ProcessEffects(false);
115  // should we check for cargo and damage after char leaves ship? maybe later
116  m_onlineModuleVec.clear();
117  m_pilot = nullptr;
118  m_isActive = false;
119  return;
120  }
121 
122  m_pilot = pClient;
123  if (pClient->IsCharCreation())
124  return;
125 
126  Init();
127 
128  // proc effects when changing ships, or on login.
129  ProcessEffects(true, sDataMgr.IsSolarSystem(locationID()));
130 
131  // this hits on login and when boarding ship in space. will not hit on Undock() (location is still station at this point of execution)
132  if (sDataMgr.IsSolarSystem(locationID())) {
133  SetFlag(flagNone);
134  /* not sure if we're gonna keep this in here....
135  if (pClient->IsLogin()) {
136  if (sConfig.debug.IsTestServer) {
137  // Heal Ship completely on test server
138  Heal();
139  } else {
140  // live server will Recharge shields and cap if session change isnt active
141  if (!m_pilot->IsSessionChange()) {
142  SetShipShield(1.0);
143  SetShipCapacitorLevel(1.0);
144  }
145  }
146  } */
147  }
148 }
149 
151 {
152  // pods have 57 attribs and 0 effects
154  InitPod();
155  return;
156  }
157 
158  InitAttribs();
159 
160  m_isActive = true;
161 
163 
164  // load linked weapons (if available)
166 
167  if (sConfig.server.CargoMassAdditive)
168  UpdateMass();
169 }
170 
176 
177  // Check for existence of attributes. if not loaded then set them to default values:
180  // shield and cap are part of persistance, and loaded on attrib map initalization. check for and set to full if no saved value found
182 
184 
185  // pod will always be full when activated
186  if (m_pilot != nullptr)
187  if (m_pilot->IsInSpace())
188  Heal();
189 }
190 
192 {
193  // Create default dynamic attributes in the AttributeMap
196  SetAttribute(AttrMass, type().mass());
199  // rig shit
201 
202  // Check for existence of attributes. if not loaded then set them to default values:
205  // shield and cap are part of persistance, and loaded on attrib map initalization. check for and set to full if no saved value found
209  // Warp Scramble Status of the ship (most ships have zero warp scramble status, but some (t2 indy) already have it defined):
214  // hull res is stored in item type as AttrHull*Resonance for 6 ships. set accordingly
219 
220  // ship bonuses....are these set in ship fx?
221  /*
222  AttrMaxRangeBonus = 351,
223  AttrDroneRangeBonus = 459,
224  AttrExplosionRangeBonus = 558,
225  AttrMaxRangeBonus2 = 769,
226 
227  */
228 
229  // cap ships have bonuses to various systems....these may be set in ship fx
230  /*
231  AttrSurveyScannerRangeBonus = 1234,
232  AttrCargoScannerRangeBonus = 1235,
233  AttrCommandBonusEffective = 1236,
234  AttrCommandBonusAdd = 1237,
235  AttrCommandBonusEffectiveAdd = 1238,
236  AttrShipBonusORECapital1 = 1239,
237  AttrShipBonusORECapital2 = 1240,
238  AttrShipBonusORECapital3 = 1243,
239  AttrShipBonusORECapital4 = 1244,
240 
241  AttrEliteBonusHeavyInterdictors1 = 1246,
242  AttrEliteBonusHeavyInterdictors2 = 1247,
243  AttrEliteBonusElectronicAttackShip1 = 1249,
244  AttrEliteBonusElectronicAttackShip2 = 1250,
245  AttrEliteBonusViolators1 = 1265,
246  AttrEliteBonusViolators2 = 1266,
247  AttrEliteBonusJumpFreighter1 = 1311,
248  AttrEliteBonusJumpFreighter2 = 1312,
249  AttrMaxTargetRangeBonusBonus = 1313,
250  AttrScanResolutionBonusBonus = 1314,
251  AttrMaxRangeBonusBonus = 1315,
252  AttrTrackingSpeedBonusBonus = 1316,
253  AttrEliteBonusViolatorsRole1 = 1268,
254  AttrEliteBonusViolatorsRole2 = 1269,
255  AttrWarpScrambleRangeBonus = 1327,
256  AttrDroneBandwidthMultiplier = 1328,
257  AttrDroneBandwidthBonusAdd = 1329,
258  AttrShipOrcaTractorBeamRangeBonus1 = 1355,
259  AttrShipOrcaCargoBonusOrca1 = 1356,
260  AttrShipOrcaTractorBeamVelocityBonus2 = 1357,
261  AttrShipOrcaForemanBonus = 1358,
262  AttrShipOrcaSurveyScannerBonus = 1359,
263  AttrShipBonusHPExtender1 = 1360,
264  AttrEliteIndustrialCovertCloakBonus = 1361,
265 
266  AttrShipBonusOreIndustrial1 = 1669,
267  AttrShipBonusOreIndustrial2 = 1670,
268 
269  AttrtitanAmarrBonus5 = 1592,
270  AttrtitanGallenteBonus5 = 1593,
271  AttrtitanMinmatarBonus5 = 1594,
272  AttrtitanCaldariBonus5 = 1596,
273 
274  */
275 
276  // t3 ships
277  /*
278  AttrSubsystemBonusAmarrEngineering = 1431,
279  AttrSubsystemBonusAmarrElectronic = 1432,
280  AttrSubsystemBonusAmarrDefensive = 1433,
281  AttrSubsystemBonusAmarrOffensive = 1434,
282  AttrSubsystemBonusAmarrPropulsion = 1435,
283  AttrSubsystemBonusGallenteEngineering = 1436,
284  AttrSubsystemBonusGallenteElectronic = 1437,
285  AttrSubsystemBonusGallenteDefensive = 1438,
286  AttrSubsystemBonusGallenteOffensive = 1439,
287  AttrSubsystemBonusGallentePropulsion = 1440,
288  AttrSubsystemBonusCaldariEngineering = 1441,
289  AttrSubsystemBonusCaldariElectronic = 1442,
290  AttrSubsystemBonusCaldariDefensive = 1443,
291  AttrSubsystemBonusCaldariOffensive = 1444,
292  AttrSubsystemBonusCaldariPropulsion = 1445,
293  AttrSubsystemBonusMinmatarEngineering = 1446,
294  AttrSubsystemBonusMinmatarElectronic = 1447,
295  AttrSubsystemBonusMinmatarDefensive = 1448,
296  AttrSubsystemBonusMinmatarOffensive = 1449,
297  AttrSubsystemBonusMinmatarPropulsion = 1450,
298 
299  AttrShipBonusStrategicCruiserAmarr = 1503,
300  AttrShipBonusStrategicCruiserCaldari = 1504,
301  AttrShipBonusStrategicCruiserGallente = 1505,
302  AttrShipBonusStrategicCruiserMinmatar = 1506,
303 
304  AttrSubsystemBonusAmarrDefensive2 = 1507,
305  AttrSubsystemBonusAmarrElectronic2 = 1508,
306  AttrSubsystemBonusAmarrEngineering2 = 1509,
307  AttrSubsystemBonusCaldariOffensive2 = 1510,
308  AttrSubsystemBonusAmarrOffensive2 = 1511,
309  AttrSubsystemBonusAmarrPropulsion2 = 1512,
310  AttrSubsystemBonusCaldariPropulsion2 = 1513,
311  AttrSubsystemBonusCaldariElectronic2 = 1514,
312  AttrSubsystemBonusCaldariEngineering2 = 1515,
313  AttrSubsystemBonusCaldariDefensive2 = 1516,
314  AttrSubsystemBonusGallenteDefensive2 = 1517,
315  AttrSubsystemBonusGallenteElectronic2 = 1518,
316  AttrSubsystemBonusGallenteEngineering2 = 1519,
317  AttrSubsystemBonusGallentePropulsion2 = 1520,
318  AttrSubsystemBonusGallenteOffensive2 = 1521,
319  AttrSubsystemBonusMinmatarOffensive2 = 1522,
320  AttrSubsystemBonusMinmatarPropulsion2 = 1523,
321  AttrSubsystemBonusMinmatarElectronic2 = 1524,
322  AttrSubsystemBonusMinmatarEngineering2 = 1525,
323  AttrSubsystemBonusMinmatarDefensive2 = 1526,
324 
325  AttrSubsystemBonusAmarrOffensive3 = 1531,
326  AttrSubsystemBonusGallenteOffensive3 = 1532,
327  AttrSubsystemBonusCaldariOffensive3 = 1533,
328  AttrSubsystemBonusMinmatarOffensive3 = 1534,
329  */
330 }
331 
335 }
336 
339  // updated to use inventory -allan 26Jul16 -fixed 22Nov18 -updated to new call 08Aug20
340  return pInventory->GetRemainingCapacity(flag);
341 }
342 
344  if (m_pilot->IsDocked())
345  return;
346 
348 }
349 
351 {
352  if (m_ModuleManager != nullptr) {
355  }
356  SaveShip();
357  // linked weapons will be persistant here.
358  //UnlinkAllWeapons();
359 }
360 
362  m_isDocking = true;
363 
365  m_onlineModuleVec.clear();
366  // remove ship effects and char skill effects for docking.
367  ProcessEffects();
368 }
369 
371  m_isUndocking = true;
372 
373  //HorribleFittingProblems
374 
375  ResetEffects();
376  //ProcessEffects(true, true);
377 
378  // horrible hack to set charge qty in fit window
379  // on the off-chance player opens the fit window
381 
382  // Recharge shields and cap if session change isnt active (undocking too fast)
383  if (!m_pilot->IsSessionChange()) {
384  SetShipShield(1.0);
386  }
387 }
388 
390 {
391  std::map< uint32, InventoryItemRef > invMap;
392  pInventory->GetInventoryMap(invMap);
393  uint32 mass(GetAttribute(AttrMass).get_uint32());
394  for (auto cur : invMap)
395  mass += cur.second->type().mass() * cur.second->quantity();
396 
397  // may have to adjust this for player login
398  SetAttribute(AttrMass, mass, HasPilot());
399 }
400 
403 }
404 
407 }
408 /* {'messageKey': 'JumpAlreadyHaveStationClone', 'dataID': 17882749, 'suppressable': False, 'bodyID': 259250, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1009}
409  * {'messageKey': 'JumpAttemptTooSoon', 'dataID': 17883129, 'suppressable': False, 'bodyID': 259393, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1010}
410  * {'messageKey': 'JumpBeaconInWormholeSpace', 'dataID': 17877290, 'suppressable': False, 'bodyID': 257194, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 2829}
411  * {'messageKey': 'JumpCantAcceptOwnInstall', 'dataID': 17883135, 'suppressable': False, 'bodyID': 259395, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1011}
412  * {'messageKey': 'JumpCantDestroyCloneInOthersShip', 'dataID': 17882752, 'suppressable': False, 'bodyID': 259251, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1012}
413  * {'messageKey': 'JumpCantDestroyCloneNoRight', 'dataID': 17882755, 'suppressable': False, 'bodyID': 259252, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1013}
414  * {'messageKey': 'JumpCantUseCFG', 'dataID': 17882760, 'suppressable': False, 'bodyID': 259254, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259253, 'messageID': 1015}
415  * {'messageKey': 'JumpCharStoringMaxClones', 'dataID': 17883140, 'suppressable': False, 'bodyID': 259397, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259396, 'messageID': 1016}
416  * {'messageKey': 'JumpCharStoringMaxClonesNone', 'dataID': 17879907, 'suppressable': False, 'bodyID': 258189, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 258188, 'messageID': 2182}
417  * {'messageKey': 'JumpCheckIntoShip', 'dataID': 17879917, 'suppressable': False, 'bodyID': 258193, 'messageType': 'question', 'urlAudio': '', 'urlIcon': '', 'titleID': 258192, 'messageID': 2187}
418  * {'messageKey': 'JumpCheckWillLoseExistingClone', 'dataID': 17882765, 'suppressable': False, 'bodyID': 259256, 'messageType': 'warning', 'urlAudio': '', 'urlIcon': '', 'titleID': 259255, 'messageID': 1017}
419  * {'messageKey': 'JumpCheckWillLoseExistingCloneAndImplants', 'dataID': 17882770, 'suppressable': False, 'bodyID': 259258, 'messageType': 'warning', 'urlAudio': '', 'urlIcon': '', 'titleID': 259257, 'messageID': 1018}
420  * {'messageKey': 'JumpCloneInstallationOffered', 'dataID': 17883248, 'suppressable': False, 'bodyID': 259436, 'messageType': 'question', 'urlAudio': '', 'urlIcon': '', 'titleID': 259435, 'messageID': 1020}
421  * {'messageKey': 'JumpCloneNotFound', 'dataID': 17882773, 'suppressable': False, 'bodyID': 259259, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1021}
422  * {'messageKey': 'JumpCriminalConfirm', 'dataID': 17877821, 'suppressable': False, 'bodyID': 257396, 'messageType': 'warning', 'urlAudio': '', 'urlIcon': '', 'titleID': 257395, 'messageID': 2544}
423  * {'messageKey': 'JumpDestinationBlocked', 'dataID': 17875972, 'suppressable': False, 'bodyID': 256704, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 256703, 'messageID': 3497}
424  * {'messageKey': 'JumpDestinationInvalid', 'dataID': 17882778, 'suppressable': False, 'bodyID': 259261, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259260, 'messageID': 1022}
425  * {'messageKey': 'JumpDestinationIsWormholeSpace', 'dataID': 17877287, 'suppressable': False, 'bodyID': 257193, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 2828}
426  * {'messageKey': 'JumpDestinationNotWilling', 'dataID': 17883025, 'suppressable': False, 'bodyID': 259352, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1023}
427  * {'messageKey': 'JumpDriveActive', 'dataID': 2039122, 'suppressable': False, 'bodyID': None, 'messageType': 'audio', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1024}
428  * {'messageKey': 'JumpHarmonicsDoNotMatch', 'dataID': 17878894, 'suppressable': False, 'bodyID': 257799, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 2383}
429  * {'messageKey': 'JumpInstalleeNotPresent', 'dataID': 17882781, 'suppressable': False, 'bodyID': 259262, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1025}
430  * {'messageKey': 'JumpInstalleeTooDistant', 'dataID': 17883170, 'suppressable': False, 'bodyID': 259408, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1026}
431  * {'messageKey': 'JumpInstallerNotPresent', 'dataID': 17882784, 'suppressable': False, 'bodyID': 259263, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1027}
432  * {'messageKey': 'JumpMustBeInPod', 'dataID': 17878190, 'suppressable': False, 'bodyID': 257533, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 257532, 'messageID': 2744}
433  * {'messageKey': 'JumpNoBridge', 'dataID': 17882789, 'suppressable': False, 'bodyID': 259265, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259264, 'messageID': 1028}
434  * {'messageKey': 'JumpNoCloneAtDestination', 'dataID': 17882792, 'suppressable': False, 'bodyID': 259266, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1029}
435  * {'messageKey': 'JumpNoDrive', 'dataID': 17882797, 'suppressable': False, 'bodyID': 259268, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259267, 'messageID': 1030}
436  * {'messageKey': 'JumpNoPortal', 'dataID': 17882802, 'suppressable': False, 'bodyID': 259270, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259269, 'messageID': 1031}
437  * {'messageKey': 'JumpNoShipCloneForAbsentChar', 'dataID': 17883173, 'suppressable': False, 'bodyID': 259409, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1032}
438  * {'messageKey': 'JumpNoShipCloneForBusyChar', 'dataID': 17883176, 'suppressable': False, 'bodyID': 259410, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1033}
439  * {'messageKey': 'JumpNoShipCloneWhenDoingShipOne', 'dataID': 17883179, 'suppressable': False, 'bodyID': 259411, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1034}
440  * {'messageKey': 'JumpNoStationCloneWhenDoingShipOne', 'dataID': 17882805, 'suppressable': False, 'bodyID': 259271, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1035}
441  * {'messageKey': 'JumpNotEnoughCap', 'dataID': 17883189, 'suppressable': False, 'bodyID': 259415, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259414, 'messageID': 1036}
442  * {'messageKey': 'JumpNotEnoughCharge', 'dataID': 17883194, 'suppressable': False, 'bodyID': 259417, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259416, 'messageID': 1037}
443  * {'messageKey': 'JumpNotEnoughCharge2', 'dataID': 17883199, 'suppressable': False, 'bodyID': 259419, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259418, 'messageID': 1038}
444  * {'messageKey': 'JumpNotEnoughCharge3', 'dataID': 17879346, 'suppressable': False, 'bodyID': 257973, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 257972, 'messageID': 2342}
445  * {'messageKey': 'JumpOtherAlreadyHasShipClone', 'dataID': 17883205, 'suppressable': False, 'bodyID': 259421, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1039}
446  * {'messageKey': 'JumpShipCloneInstallAcceptTooLate', 'dataID': 17882808, 'suppressable': False, 'bodyID': 259272, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1040}
447  * {'messageKey': 'JumpShipCloneInstallAcceptWTF', 'dataID': 17882811, 'suppressable': False, 'bodyID': 259273, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1041}
448  * {'messageKey': 'JumpShipCloneInstallCancelTooLate', 'dataID': 17882814, 'suppressable': False, 'bodyID': 259274, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1042}
449  * {'messageKey': 'JumpShipCloneInstallCancelWTF', 'dataID': 17882817, 'suppressable': False, 'bodyID': 259275, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1043}
450  * {'messageKey': 'JumpShipLacksActiveCloneVatBay', 'dataID': 17877847, 'suppressable': False, 'bodyID': 257406, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 2557}
451  * {'messageKey': 'JumpShipLacksCloneSupport', 'dataID': 17882820, 'suppressable': False, 'bodyID': 259276, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1044}
452  * {'messageKey': 'JumpShipNotOwnedByCharacter', 'dataID': 17882823, 'suppressable': False, 'bodyID': 259277, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1045}
453  * {'messageKey': 'JumpShipStoringMaxClones', 'dataID': 17883211, 'suppressable': False, 'bodyID': 259423, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1046}
454  * {'messageKey': 'JumpSkillInTraining', 'dataID': 17880967, 'suppressable': False, 'bodyID': 258596, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 1817}
455  * {'messageKey': 'JumpSuperweaponActive', 'dataID': 17879575, 'suppressable': False, 'bodyID': 258058, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 258057, 'messageID': 2306}
456  * {'messageKey': 'JumpTooFar', 'dataID': 17883219, 'suppressable': False, 'bodyID': 259426, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 259425, 'messageID': 1047}
457  */
459 {
460  // Repair Ship, Modules and Recharge Capacitor:
461  SetShipShield(1.0);
463  SetShipArmor(1.0);
464  SetShipHull(1.0);
466 }
467 
469 {
470  if (iRef.get() == nullptr)
471  return;
472 
474 
475  // add item mass to ship's mass if set in options (additive...loaded ship should be heavy)
476  if (sConfig.server.CargoMassAdditive) {
478  uint32 addition = iRef->type().mass() * iRef->quantity();
479  SetAttribute(AttrMass, mass + addition, HasPilot());
480  }
481 
483 }
484 
485 // cannot throw
487 {
488  if (iRef.get() == nullptr)
489  return 0;
490 
491  if (flag == flagNone) {
492  // make error. nothing at this point should be "autoFit"
493  codelog(SHIP__ERROR, "ShipItem::AddItem() - flag = flagNone.");
494  if (sConfig.debug.IsTestServer)
495  EvE::traceStack();
496  flag = flagCargoHold; //default to cargo (cause this is a ship)
497  }
498  // CantFitModuleToThatShip
499  // u'CantFitModuleToThatShipBody'}(u"You can't fit {item} to {ship}", None, {u'{ship}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'ship'}, u'{item}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'item'}})
500 
501  if (IsModuleSlot(flag)) {
502  if (iRef->categoryID() == EVEDB::invCategories::Charge) {
503  iRef->ChangeSingleton(false, false);
504  m_ModuleManager->LoadCharge(iRef, flag);
506  if (iRef.get() == nullptr)
507  return 0;
508  return iRef->itemID();
509  } else if (iRef->categoryID() == EVEDB::invCategories::Module) {
511  mRef->ChangeSingleton(true, false);
512  // rigs are classed in the module category. check here and call appropriate method as needed.
513  if (IsRigSlot(flag)) {
514  if (!m_ModuleManager->InstallRig(mRef, flag))
515  return 0;
516  } else if (!m_ModuleManager->AddModule(mRef, flag))
517  return 0;
518  } else if (iRef->categoryID() == EVEDB::invCategories::Subsystem) {
520  //mRef->SetOnline(true); // is this needed here?
521  mRef->ChangeSingleton(true, false);
522  if (!m_ModuleManager->InstallSubSystem(mRef, flag))
523  return 0;
524  }
525  //m_ModuleManager->UpdateModules(flag);
526  }
527 
528  iRef->Move(m_itemID, flag, true);
529  return iRef->itemID();
530 }
531 
533 {
534  if (iRef.get() == nullptr)
535  return;
536 
538 
539  if (m_pilot == nullptr)
540  return;
541 
542  // check to see if item is currently in a module slot.
543  if (IsModuleSlot(iRef->flag())) {
544  if (IsRigSlot(iRef->flag())) {
546  } else if (iRef->categoryID() == EVEDB::invCategories::Charge) {
548  } else {
550  }
551  //m_ModuleManager->UpdateModules(iRef->flag());
552  }
553 
554  // remove item mass to ship's mass if set in options (additive...loaded ship should be heavy)
555  if (sConfig.server.CargoMassAdditive) {
557  uint32 addition = iRef->type().mass() * iRef->quantity();
558  SetAttribute(AttrMass, mass - addition, HasPilot());
559  }
560 }
561 
563 {
564  m_onlineModuleVec.push_back(modID);
565  _log(MODULE__INFO, "Added ModuleID %u to Online List", modID);
566 }
567 
568 void ShipItem::GetModuleItemVec( std::vector< InventoryItemRef >& iRefVec ) {
569  std::map<uint32, InventoryItemRef> invMap;
570  pInventory->GetInventoryMap( invMap );
571  for (auto cur : invMap )
572  if (IsModuleSlot(cur.second->flag()))
573  iRefVec.push_back(cur.second);
574 }
575 
576 /* Begin new Module Manager Interface */
577 void ShipItem::GetModuleRefVec(std::vector< InventoryItemRef >& iRefVec)
578 {
580 }
581 
583 {
585  if (pMod != nullptr)
586  return pMod->GetSelf();
587 
588  return InventoryItemRef(nullptr);
589 }
590 
592 {
593  GenericModule* pMod(m_ModuleManager->GetModule(modID));
594  if (pMod != nullptr)
595  return pMod->GetSelf();
596 
597  return InventoryItemRef(nullptr);
598 }
599 
600 // only called from dogma call. can throw
602 {
603  if (cRef.get() == nullptr)
604  throw UserError ("CantFindChargeToAdd");
605 
606  if (!IsFittingSlot(flag))
607  throw CustomError ("Destination is not weapon.");
608 
609  if (IsFittingSlot(cRef->flag())) {
610  _log(MODULE__TRACE, "ShipItem::LoadCharge - Trying to load %s from %s to %s.", \
611  cRef->name(), sDataMgr.GetFlagName(cRef->flag()), sDataMgr.GetFlagName(flag));
612  throw UserError ("CantMoveChargesBetweenModules");
613  }
614 
616  if (pMod == nullptr)
617  throw UserError ("ModuleNoLongerPresentForCharges");
618 
619  if (pMod->IsActive()) {
620  throw CustomError ("You cannot load active modules.");
621  /*
622  std::map<std::string, PyRep *> args;
623  args["chargeType"] = new PyInt(iRef->typeID());
624  throw PyException( MakeUserError("LoadingChargeSlotAlready", args)); */
625  /*LoadingChargeSlotAlreadyBody'}(u'You cannot load the {[item]chargeType.name} because the module is already involved in another loading operation.'
626  * , None, {u'{[item]chargeType.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'chargeType'}})
627  */
628  }
629  if (pMod->GetModuleState() == Module::State::Loading) {
630  throw UserError ("LoadingChargeSlotAlready")
631  .AddFormatValue ("chargeType", new PyInt (cRef->typeID ()));
632  //throw PyException( MakeUserError("LoadingChargeAlready", args));
633  /*LoadingChargeAlreadyBody'}(u'Some or all of {[item]chargeType.name} is already being loaded into a module.
634  * If you wish to load what remains, you will have to wait until this is finished.',
635  * None, {u'{[item]chargeType.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'chargeType'}})
636  */
637  }
638 
639  VerifyHoldType(flag, cRef, m_pilot);
640  /* this doesnt work right....comment for now.
641  std::map<std::string, PyRep *> args;
642  args["charge"] = new PyInt(iRef->itemID());
643  throw UserError ("ChargeLoadingFailedWithRefund");
644  */
645  /* ChargeLoadingFailedWithRefundBody'}(u'Your {[item]charge.name} failed to load and was returned to your cargo.',
646  * None, {u'{[item]charge.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'charge'}})
647  */
648  m_ModuleManager->LoadCharge(cRef, flag);
649 }
650 /*
651  * ChargeRequiresLauncher
652  * DragDropCharge ??
653 
654  * IncompatibleChargeGroup1 {'FullPath': u'UI/Messages', 'messageID': 259621, 'label': u'IncompatibleChargeGroup1Body'}(u'You cannot load {ammoGroup} into a {[item]moduleName.name}, this module needs to be loaded with {group1}.', None, {u'{ammoGroup}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'ammoGroup'}, u'{[item]moduleName.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'moduleName'}, u'{group1}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'group1'}})
655 NotEnoughChargeSpace {'FullPath': u'UI/Messages', 'messageID': 259162, 'label': u'NotEnoughChargeSpaceBody'}(u'There is not enough space to add those charges. There is only {[numeric]capacity, decimalPlaces=2} {[numeric]capacity -> "unit", "units"} of space, but the charges require {[numeric]volume, decimalPlaces=2} {[numeric]volume -> "unit", "units"}.', None, {u'{[numeric]capacity, decimalPlaces=2}': {'conditionalValues': [], 'variableType': 9, 'propertyName': None, 'args': 512, 'kwargs': {'decimalPlaces': 2}, 'variableName': 'capacity'}, u'{[numeric]capacity -> "unit", "units"}': {'conditionalValues': [u'unit', u'units'], 'variableType': 9, 'propertyName': None, 'args': 320, 'kwargs': {}, 'variableName': 'capacity'}, u'{[numeric]volume, decimalPlaces=2}': {'conditionalValues': [], 'variableType': 9, 'propertyName': None, 'args': 512, 'kwargs': {'decimalPlaces': 2}, 'variableName': 'volume'}, u'{[numeric]volume -> "unit", "units"}': {'conditionalValues': [u'unit', u'units'], 'variableType': 9, 'propertyName': None, 'args': 320, 'kwargs': {}, 'variableName': 'volume'}})
656 {'FullPath': u'UI/Messages', 'messageID': 257216, 'label': u'NoSuitableModulesBody'}(u'These charges cannot be fitted to any of the currently fitted modules', None, None)
657 
658  */
659 
660 // only called from dogma call. can throw
661 void ShipItem::LoadChargesToBank(EVEItemFlags flag, std::vector< int32 >& chargeIDs)
662 {
663  int8 pos = 0;
664  InventoryItemRef cRef(nullptr);
665  std::vector<GenericModule*> modVec;
666  m_ModuleManager->GetModulesInBank(flag, modVec);
667  for (auto cur : modVec) {
668  if (pos + 1 > chargeIDs.size())
669  return;
670  cRef = sItemFactory.GetItem(chargeIDs[pos]);
671  if (cRef.get() == nullptr) {
672  ++pos;
673  continue;
674  }
675  if (IsCargoHoldFlag(cRef->flag()) or IsHangarFlag(cRef->flag())) {
676  LoadCharge(cRef, cur->flag());
677  } else {
678  ++pos;
679  }
680  }
681 }
682 
683 // only called from dogma call. can throw
684 void ShipItem::LoadLinkedWeapons(GenericModule* pMod, std::vector<int32>& chargeIDs)
685 {
686  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod);
687  if (itr == m_linkedWeapons.end())
688  return;
689 
690  int8 pos = 0;
691  InventoryItemRef cRef(sItemFactory.GetItem(chargeIDs[pos]));
692  if (cRef.get() == nullptr)
693  throw UserError ("CantFindChargeToAdd");
694 
695  int8 size(chargeIDs.size());
696  //load charge in master
697  VerifyHoldType(pMod->flag(), cRef, m_pilot);
698  m_ModuleManager->LoadCharge(cRef, pMod->flag());
699  // loop thru slaves and load charge(s)
700  std::list<GenericModule*>::iterator itr2 = itr->second.begin();
701  while ((itr2 != itr->second.end()) and (pos <= size)) {
702  cRef = sItemFactory.GetItem(chargeIDs[pos]);
703  if (cRef.get() == nullptr){
704  ++pos;
705  } else if (IsCargoHoldFlag(cRef->flag()) or IsHangarFlag(cRef->flag())) {
706  VerifyHoldType((*itr2)->flag(), cRef, m_pilot);
707  m_ModuleManager->LoadCharge(cRef, (*itr2)->flag());
708  ++itr2;
709  } else {
710  ++pos;
711  }
712  }
713 }
714 
715 //{'FullPath': u'UI/Messages', 'messageID': 257270, 'label': u'NotEnoughCargoSpaceToUnloadBankBody'}(u'There is not enough cargo space left to unload the charges in the weapon bank. Try freeing up some space and try again.', None, None)
716 
717 // only called from client call. can throw
719 {
720  if (IsFittingSlot(fromFlag)) {
721  GenericModule* pMod(m_ModuleManager->GetModule(fromFlag));
722  if (pMod == nullptr)
723  throw CustomError ("Module was not found at %s.", sDataMgr.GetFlagName(fromFlag));
724 
725  if (pMod->IsActive())
726  throw UserError ("CannotAccessChargeWhileInUse");
727 
728  if (!pMod->IsLoaded())
729  throw CustomError ("Your %s is not loaded.", pMod->GetSelf()->name());
730 
732  }
733 }
734 
735 // only called from inv bound call. can throw
737 {
738  if (m_ModuleManager->IsSlotOccupied(flag))
739  throw UserError ("SlotAlreadyOccupied");
740 
743 
744  if (IsHiSlot(flag)) {
745  // check available turret/launcher hardpoints
748  throw UserError ("NotEnoughTurretSlots")
749  .AddTypeName ("moduleName", iRef->typeID ());
750  /*u'NotEnoughTurretSlotsBody'}(u"You cannot fit the {moduleName} because your ship doesn't have any turret slots left for fitting, possibly because you have already filled your ship with turrets or that the ship simply can not be fitted with turrets.\r\n<br>
751  * <br>Turret slots represent how many weapons of a certain type can be fitted on a ship. The current design is over a hundred years old, and is modular enough to allow for a great leeway in the fitting of various weaponry.", None,
752  * {u'{moduleName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'moduleName'}})
753  */
754  }
755  } else if (iRef->type().HasEffect(EVEEffectID::launcherFitted)) {
757  throw UserError ("NotEnoughLauncherSlots")
758  .AddTypeName ("moduleName", iRef->typeID ());
759  /*NotEnoughLauncherSlotsBody'}(u"You cannot fit the {moduleName} because your ship doesn't have any launcher slots left for fitting, possibly because you have already filled your ship with launchers or that the ship simply can not be fitted with launchers.<br>
760  * <br>Launcher slots represent how many weapons of a certain type can be fitted on a ship. The current design is over a hundred years old, and is modular enough to allow for a great leeway in the fitting of various weaponry.", None,
761  * {u'{moduleName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'moduleName'}})
762  */
763  }
764  }
765  } else if (IsRigSlot(flag)) {
767  throw UserError ("CannotFitRigWrongSize")
768  .AddFormatValue ("rigSize", new PyString (sDataMgr.GetRigSizeName (iRef->GetAttribute (AttrRigSize).get_uint32())))
769  .AddTypeName ("item", iRef->typeID ())
770  .AddFormatValue ("shipRigSize", new PyString (sDataMgr.GetRigSizeName (GetAttribute (AttrRigSize).get_uint32())));
771  /* CannotFitRigWrongSizeBody'}(u'{item} does not fit in this slot.
772  * The slot takes size {shipRigSize} rigs, but the item is size {rigSize}.', None,
773  * {u'{rigSize}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'rigSize'},
774  * u'{item}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'item'},
775  * u'{shipRigSize}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'shipRigSize'}})
776  * check avalible rig slots and ship upgrade capy
777  */
778  }
780  throw UserError ("NotEnoughUpgradeSlots")
781  .AddFormatValue ("moduleType", new PyInt (iRef->typeID ()));
782  /*NotEnoughUpgradeSlotsBody'}(u"You cannot fit the {[item]moduleType.name} because your ship doesn't have any upgrade slots left for fitting, possibly because you have already filled your ship with upgrades or that the ship simply can not be fitted with upgrades.", None,
783  * {u'{[item]moduleType.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'moduleType'}})
784  */
785  }
786 
788  throw UserError ("NotEnoughUpgradeCapacity")
789  .AddTypeName ("moduleName", iRef->typeID ());
790  /*NotEnoughUpgradeCapacityBody'}(u'You cannot fit the {moduleName} because your ship cannot handle it. Your ship can only fit so many upgrades as each interferes with its calibration, and past a certain point your ship is rendered unusable.', None,
791  * {u'{moduleName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'moduleName'}})
792  */
793  }
794  }
795 }
796 
798  uint16 slotFound(flagIllegal);
799  if (iRef->type().HasEffect(EVEEffectID::loPower)) {
801  } else if (iRef->type().HasEffect(EVEEffectID::medPower)) {
803  } else if (iRef->type().HasEffect(EVEEffectID::hiPower)) {
805  } else if (iRef->type().HasEffect(EVEEffectID::subSystem)) {
807  } else if (iRef->type().HasEffect(EVEEffectID::rigSlot)) {
809  } else {
810  codelog(SHIP__ERROR, "ShipItem::FindAvailableModuleSlot() - iRef %s has no bank effect.", iRef->name());
811  }
812 
813  return (EVEItemFlags)slotFound;
814 }
815 
816 
817 // only called from inv bound call. can throw
819  // this will never hit. client checks before call.
820  if (!m_ModuleManager->VerifySlotExchange(slot1, slot2))
821  throw CustomError ("Those locations are not compatible.");
822 
823  // test for active module(s) before moving
824  GenericModule* pMod(GetModule(slot1));
825  if (pMod->IsActive())
826  throw CustomError ("Your %s is currently active. You must wait for the cycle to complete before it can be removed.", pMod->GetSelf()->name());
827 
828  pMod = GetModule(slot2);
829  if (pMod != nullptr)
830  if (pMod->IsActive())
831  throw CustomError ("Your %s is currently active. You must wait for the cycle to complete before it can be removed.", pMod->GetSelf()->name());
832 
833  // slot1 is occupied, as this is where module is from.
834  InventoryItemRef modItemRef1(GetModuleRef(slot1));
835  if (modItemRef1.get() == nullptr) {
836  _log(MODULE__TRACE, "ShipItem::MoveModuleSlot - modItemRef1 is null.");
837  throw CustomError ("The module to move was not found.");
838  }
840  RemoveItem(modItemRef1);
841 
842  if (m_ModuleManager->IsSlotOccupied(slot2)) {
843  // dropped-on slot is occupied. proceed with moving the module currently in this slot.
844  InventoryItemRef modItemRef2 = GetModuleRef(slot2);
846  RemoveItem(modItemRef2);
847  AddItemByFlag(slot1, modItemRef2);
848  if (modItemRef2->GetAttribute(AttrOnline).get_bool())
849  m_ModuleManager->Online(slot1);
850  if (chargeItemRef2.get() != nullptr)
851  m_ModuleManager->LoadCharge(chargeItemRef2, slot1);
852  }
853 
854  AddItemByFlag(slot2, modItemRef1);
855  if (modItemRef1->GetAttribute(AttrOnline).get_bool())
856  m_ModuleManager->Online(slot2);
857 
858  if (chargeItemRef1.get() != nullptr)
859  m_ModuleManager->LoadCharge(chargeItemRef1, slot2);
860 }
861 
863 {
864  /* this is only called when ship is in space
865  * this will call Online() on all modules, which will apply passive and online effects.
866  */
868  m_onlineModuleVec.clear();
869  //FailedToOnlineModulesOnUndock
870 }
871 
873 {
874  // List of callees to put this function into context as to what it should be doing:
875  // ShipSE::AddItem()
876  // Client::MoveItem() - something has been moved into or out of the ship, recheck all modules for... some reason
878 }
879 
880 // Updated fractional ship defense settings. -allan 1Feb15
882 {
883  if (fraction > 1.0) fraction = 1.0;
884  if (fraction < 0.0) fraction = 0.0;
885 
886  EvilNumber newCapacitorCharge(EvilZero);
887  newCapacitorCharge = GetAttribute(AttrCapacitorCapacity) * fraction;
888  if ((newCapacitorCharge + 0.5f) > GetAttribute(AttrCapacitorCapacity).get_float())
889  newCapacitorCharge = GetAttribute(AttrCapacitorCapacity);
890  if ((newCapacitorCharge - 0.5f) < 0)
891  newCapacitorCharge = 0;
892 
893  _log(SHIP__MESSAGE, "SetShipCapacitorLevel() to %.1f%%. new value is %.1f", fraction, newCapacitorCharge.get_float());
894  SetAttribute(AttrCapacitorCharge, newCapacitorCharge);
895 }
896 
897 void ShipItem::SetShipShield(float fraction)
898 {
899  if (fraction > 1.0) fraction = 1.0;
900  if (fraction < 0.0) fraction = 0.0;
901 
902  EvilNumber newShieldCharge(EvilZero);
903  newShieldCharge = GetAttribute(AttrShieldCapacity) * fraction;
904  if ((newShieldCharge + 0.2f) > GetAttribute(AttrShieldCapacity).get_float())
905  newShieldCharge = GetAttribute(AttrShieldCapacity);
906  if ((newShieldCharge - 0.2f) < 0)
907  newShieldCharge = 0;
908 
909  _log(SHIP__MESSAGE, "SetShipShield() to %.1f%%. new value is %.1f", fraction, newShieldCharge.get_float());
910  SetAttribute(AttrShieldCharge, newShieldCharge);
911 }
912 
913 void ShipItem::SetShipArmor(float fraction)
914 {
915  fraction = 1 - fraction;
916 
917  if (fraction > 1.0) fraction = 1.0;
918  if (fraction < 0.0) fraction = 0.0;
919 
920  EvilNumber newArmorDamage(EvilZero);
921  newArmorDamage = GetAttribute(AttrArmorHP) * fraction;
922  if ((newArmorDamage + 0.2f) > GetAttribute(AttrArmorHP).get_float())
923  newArmorDamage = GetAttribute(AttrArmorHP);
924  if ((newArmorDamage - 0.2f) < 0)
925  newArmorDamage = 0;
926 
927  _log(SHIP__MESSAGE, "SetShipArmor() to %.1f%%. new value is %.1f", fraction, newArmorDamage.get_float());
928  SetAttribute(AttrArmorDamage, newArmorDamage);
929 }
930 
931 void ShipItem::SetShipHull(float fraction)
932 {
933  fraction = 1 - fraction;
934 
935  if (fraction > 1.0) fraction = 1.0;
936  if (fraction < 0.0) fraction = 0.0;
937 
938  EvilNumber newHullDamage(EvilZero);
939  newHullDamage = GetAttribute(AttrHP) * fraction;
940  if ((newHullDamage + 0.2f) > GetAttribute(AttrHP).get_float())
941  newHullDamage = GetAttribute(AttrHP);
942  if ((newHullDamage - 0.2f) < 0)
943  newHullDamage = 0;
944 
945  _log(SHIP__MESSAGE, "SetShipHull() to %.1f%%. new value is %.1f", fraction, newHullDamage.get_float());
946  SetAttribute(AttrDamage, newHullDamage);
947 }
948 
949 // not used
950 void ShipItem::RepairShip(float fraction)
951 {
952  if (fraction > 1)
953  fraction = 1;
954 
955  if (fraction == 1) {
958  return;
959  }
960 
961  uint32 cHull(GetAttribute(AttrDamage).get_uint32());
962  uint32 cArmor(GetAttribute(AttrArmorDamage).get_uint32());
963  uint32 damage(cHull + cArmor);
964  EvilNumber amount(damage * fraction);
965  // this will repair hull first, then armor
966  if (amount > cHull) {
967  amount -= cHull;
969  if (amount >= cArmor) {
971  } else {
972  amount = cArmor - amount;
973  SetAttribute(AttrArmorDamage, amount);
974  }
975  } else {
976  SetAttribute(AttrDamage, amount);
977  }
978 }
979 
980 // not used
981 void ShipItem::RepairModules(std::vector<InventoryItemRef>& itemRefVec, float fraction)
982 {
985  for (auto cur : itemRefVec) {
986  damage = cur->GetAttribute(AttrDamage);
987  if (damage < 0.01)
988  continue;
989  amount = cur->GetAttribute(AttrDamage);
990  if ((amount / cur->GetAttribute(AttrHP)) > fraction) {
991  amount = cur->GetAttribute(AttrHP) * fraction;
992  } else {
993  amount = 1;
994  }
995  m_ModuleManager->RepairModule(cur->itemID(), amount);
996  }
997 }
998 
1000 {
1001  if (sDataMgr.IsSolarSystem(locationID())) {
1002  ; // check for avalible cap, and drain accordingly (this can throw)
1003  /*
1004  float Charge = GetAttribute(AttrCapacitorCharge).get_float();
1005  float Capacity = GetAttribute(AttrCapacitorCapacity).get_float();
1006  float newCharge = 0;
1007  SetAttribute(AttrCapacitorCharge, newCharge);
1008  _log(SHIP__MESSAGE, "ShipItem::Online(): %s(%u) - New Cap Charge: %f", GetPilot()->GetName(), itemID(), newCharge);
1009  */
1010  }
1011  /* {'messageKey': 'EffectAlreadyActive2', 'dataID': 17876243, 'suppressable': False, 'bodyID': 256802, 'messageType': 'hint', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 3252}
1012  * {'messageKey': 'EffectCantHaveNegativeDuration', 'dataID': 17883801, 'suppressable': False, 'bodyID': 259632, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 847}
1013  * {'messageKey': 'EffectCrowdedOut', 'dataID': 17883719, 'suppressable': False, 'bodyID': 259602, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 848}
1014  * {'messageKey': 'EffectDeactivationCloaking', 'dataID': 17883455, 'suppressable': False, 'bodyID': 259510, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 849}
1015  * {'messageKey': 'EffectDeactivationWarping', 'dataID': 17883458, 'suppressable': False, 'bodyID': 259511, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 850}
1016  * {'messageKey': 'EffectNotActivatible', 'dataID': 17880378, 'suppressable': False, 'bodyID': 258369, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 2228}
1017  * {'messageKey': 'EffectNotDeactivatible', 'dataID': 17883847, 'suppressable': False, 'bodyID': 259649, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 851}
1018  * {'messageKey': 'EffectStillActivating', 'dataID': 17883850, 'suppressable': False, 'bodyID': 259650, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 852}
1019  * {'messageKey': 'EffectStillActive', 'dataID': 17883853, 'suppressable': False, 'bodyID': 259651, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 853}
1020  */
1021  /*{'FullPath': u'UI/Messages', 'messageID': 256802, 'label': u'EffectAlreadyActive2Body'}(u'{modulename} is already active', None, {u'{modulename}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'modulename'}})
1022  * {'FullPath': u'UI/Messages', 'messageID': 258369, 'label': u'EffectNotActivatibleBody'}(u'You do not have the ability to engage the {moduleName} in that action.', None, {u'{moduleName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'moduleName'}})
1023  * {'FullPath': u'UI/Messages', 'messageID': 259510, 'label': u'EffectDeactivationCloakingBody'}(u'As certain activated effects interfere with the warping process, these are automatically being deactivated before the warp proceeds.', None, None)
1024  * {'FullPath': u'UI/Messages', 'messageID': 259511, 'label': u'EffectDeactivationWarpingBody'}(u'As certain activated effects interfere with the warping process, these are automatically being deactivated before the warp proceeds.', None, None)
1025  * {'FullPath': u'UI/Messages', 'messageID': 259602, 'label': u'EffectCrowdedOutBody'}(u'The {[item]module.name} cannot be activated as it requires access to resources and/or skills which {[numeric]count} modules of the same purpose are already using up.', None, {u'{[numeric]count}': {'conditionalValues': [], 'variableType': 9, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'count'}, u'{[item]module.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'module'}})
1026  * {'FullPath': u'UI/Messages', 'messageID': 259632, 'label': u'EffectCantHaveNegativeDurationBody'}(u'{modulename} has somehow come to have a negative duration of {duration} and cannot operate. If you know how, obtain a breakdown of its modifiers and report it, otherwise submit a detailed bug report.', None, {u'{modulename}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'modulename'}, u'{duration}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'duration'}})
1027  * {'FullPath': u'UI/Messages', 'messageID': 259649, 'label': u'EffectNotDeactivatibleBody'}(u'The {moduleName} cannot be interrupted in that action.', None, {u'{moduleName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'moduleName'}})
1028  * {'FullPath': u'UI/Messages', 'messageID': 259650, 'label': u'EffectStillActivatingBody'}(u'The {moduleName} cannot be manually deactivated while it is still being activated.', None, {u'{moduleName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'moduleName'}})
1029  * {'FullPath': u'UI/Messages', 'messageID': 259651, 'label': u'EffectStillActiveBody'}(u'The {[item]moduleTypeID.name} cannot be manually deactivated in the middle of an operation, it will deactivate without repeating in {[timeinterval]timeLeft.writtenForm, from=second, to=second} (its activation duration is {[timeinterval]duration.writtenForm, from=second, to=second}).', None, {u'{[timeinterval]timeLeft.writtenForm, from=second, to=second}': {'conditionalValues': [], 'variableType': 8, 'propertyName': 'writtenForm', 'args': 0, 'kwargs': {'to': 'second', 'from': 'second'}, 'variableName': 'timeLeft'}, u'{[timeinterval]duration.writtenForm, from=second, to=second}': {'conditionalValues': [], 'variableType': 8, 'propertyName': 'writtenForm', 'args': 0, 'kwargs': {'to': 'second', 'from': 'second'}, 'variableName': 'duration'}, u'{[item]moduleTypeID.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'moduleTypeID'}})
1030  */
1031  m_ModuleManager->Online(modID);
1032 }
1033 
1035 {
1036  m_ModuleManager->Offline(modID);
1037 }
1038 
1039 void ShipItem::Activate(int32 itemID, std::string effectName, int32 targetID, int32 repeat)
1040 {
1041  if (IsValidTarget(targetID)) {
1042  m_targetRef = sItemFactory.GetItem(targetID);
1043  } else {
1044  m_targetRef = InventoryItemRef(nullptr);
1045  }
1046 
1047  m_ModuleManager->Activate( itemID, sFxDataMgr.GetEffectID(effectName), targetID, repeat);
1048 }
1049 
1051 {
1053 }
1054 
1056 {
1058 }
1059 
1061 {
1062  SaveItem(); // Save ship info
1063  pAttributeMap->SaveShipState(); // save ship damage
1064  m_ModuleManager->SaveModules(); // Save item info for modules fitted to this ship
1065 }
1066 
1068  if (iRef.get() == nullptr)
1069  return;
1071  iRef->Move(itemID(), flagCargoHold, true);
1072 }
1073 
1075 {
1076  _log(MODULE__ERROR, "ReplaceCharges() called by %s(%u). It still needs to be written.", name(), itemID());
1077 }
1078 
1079 
1080 /* heat-related shit......
1081  * see also file:///home/allan/Desktop/backups/GoonSwarm_wiki/www.eveinfo.net/wiki/ind~2149.htm - "Thermodynamics"
1082  *
1083  AttrHeatGenerationMultiplier = 1224,
1084  AttrHeatHi = 1175,
1085  AttrHeatMed = 1176,
1086  AttrHeatLow = 1177,
1087 
1088  AttrHeatDissipationRateHi = 1179,
1089  AttrHeatDissipationRateMed = 1196,
1090  AttrHeatDissipationRateLow = 1198,
1091 
1092  AttrHeatCapacityHi = 1178,
1093  AttrHeatCapacityMed = 1199,
1094  AttrHeatCapacityLow = 1200,
1095 
1096  AttrHeatAttenuationHi = 1259,
1097  AttrHeatAttenuationMed = 1261,
1098  AttrHeatAttenuationLow = 1262,
1099 
1100  AttrHeatAbsorbtionRateModifier = 1180, // active modules only
1101 
1102  created ship attribs (rifter)
1103  1179 heatDissipationRateHi NULL 0.01
1104  1196 heatDissipationRateMed NULL 0.01
1105  1198 heatDissipationRateLow NULL 0.01
1106  1178 heatCapacityHi NULL 100
1107  1199 heatCapacityMed NULL 100
1108  1200 heatCapacityLow NULL 100
1109  1224 heatGenerationMultiplier NULL 1
1110  1259 heatAttenuationHi NULL 0.63
1111  1261 heatAttenuationMed NULL 0.5
1112  1262 heatAttenuationLow NULL 0.5
1113  created module attribs (200mm ac)
1114  1180 heatAbsorbtionRateModifier NULL 0.01
1115  1211 heatDamage NULL 1
1116  (1mn ab I)
1117  1180 heatAbsorbtionRateModifier NULL 0.04
1118  1211 heatDamage NULL 9.6
1119  (sebo I)
1120  1180 heatAbsorbtionRateModifier NULL 0.01
1121  1211 heatDamage NULL 3.4
1122 
1123  // these are calculated from fx shit (not saved) {cannot find where these are used..}
1124  AttrHeatAbsorbtionRateHi = 1182, eID 10326
1125  AttrHeatAbsorbtionRateMed = 1183, eID 10327
1126  AttrHeatAbsorbtionRateLow = 1184, eID 10328
1127 
1128 */
1129 
1131 {
1132  double start = GetTimeUSeconds();
1133  float heat(0.0f);
1134  // heat loop
1135  for (uint16 i = AttrHeatHi; i < AttrHeatLow + 1; ++i) {
1136  heat = GetAttribute(i).get_float();
1137  // the ordering here is important
1138  //heat -= log(-(heat + 1));
1139  if (heat > 1.0f)
1140  heat -= DissipateHeat(i, heat);
1141  heat += GenerateHeat(i);
1142  if (heat > 1.0f) { // not concerned about anything < 1
1143  if (heat > 100)
1144  heat = 100.0f;
1145  SetAttribute(i, heat);
1146  } //else
1147  // DeleteAttribute(i);
1148  heat = 0.0f;
1149  }
1150  _log(SHIP__HEAT, "ShipItem::ProcessHeat() Executed in %.3f us.", GetTimeUSeconds() - start);
1151 
1152  /* proc times with 3 banks of 8 modules each (from 0 - 3 modules actived)
1153 13:05:44 [ShipHeat] ShipItem::ProcessHeat() Executed in 867.000 us.
1154 13:05:50 [ShipHeat] ShipItem::ProcessHeat() Executed in 1205.000 us.
1155 13:05:56 [ShipHeat] ShipItem::ProcessHeat() Executed in 1051.500 us.
1156 13:06:02 [ShipHeat] ShipItem::ProcessHeat() Executed in 1665.750 us.
1157 13:06:08 [ShipHeat] ShipItem::ProcessHeat() Executed in 1108.500 us.
1158 13:06:14 [ShipHeat] ShipItem::ProcessHeat() Executed in 1090.250 us.
1159 13:06:20 [ShipHeat] ShipItem::ProcessHeat() Executed in 1011.250 us.
1160 13:06:26 [ShipHeat] ShipItem::ProcessHeat() Executed in 938.500 us.
1161  */
1162 }
1163 
1165 {
1174  /* heat buildup
1175  * H = 3(e^t)
1176  * t = (sum of active module's heat damage / 10) + 1
1177  * t must be > 1.0 to avoid negatives. if no modules active, t=1.0 and log(1.0)=0
1178  * this may look funny, but is rather accurate generation of module heat from normal op.
1179  */
1180 
1181  float t(1.0f);
1182  std::string rack = "";
1183  //std::vector< GenericModule* > modVec;
1184  switch(attrID) {
1185  case AttrHeatHi: {
1186  rack = "Hi";
1187  //m_ModuleManager->GetActiveModules(EVEEffectID::hiPower, modVec);
1189  } break;
1190  case AttrHeatMed: {
1191  rack = "Mid";
1193  } break;
1194  case AttrHeatLow: {
1195  rack = "Low";
1197  } break;
1198  default: {
1199  _log(SHIP__HEAT, "GenerateHeat() - %s invalid rack sent (%u)", name(), attrID);
1200  return 0;
1201  } break;
1202  }
1203 
1204  if (t < 1.2)
1205  return 0;
1206 
1207  //log(t) *3; //0.28 when t=1.1, 1.2 when t=1.5, 4.1 when t=3.9 (highest i found), 6.8 when t=5.55
1208  float heat = log(t) *3 * GetAttribute(AttrHeatGenerationMultiplier).get_float();
1209 
1210  _log(SHIP__HEAT, "%s generated %.2f heat points from the %s rack this tic. t = %.3f", name(), heat, rack.c_str(), t);
1211  return heat;
1212 }
1213 
1214 float ShipItem::DissipateHeat(uint16 attrID, float heat)
1215 {
1216  //H = ln^t
1217  float t(1.0f + heat), newHeat(0.0f);
1218  std::string rack = "";
1219  switch(attrID) {
1220  case AttrHeatHi: {
1221  rack = "Hi";
1222  } break;
1223  case AttrHeatMed: {
1224  rack = "Mid";
1225  } break;
1226  case AttrHeatLow: {
1227  rack = "Low";
1228  } break;
1229  default: {
1230  _log(SHIP__HEAT, "DissipateHeat() - %s invalid rack sent (%u)", name(), attrID);
1231  return 0.0f;
1232  } break;
1233  }
1234 
1235  newHeat = log(t); //0.18 when t=1.2, 3.1 when t=21.9, 3.9 when t=51.9, 4.6 when t=99.9
1236 
1237  if (newHeat < 0)
1238  newHeat = 0.0f;
1239 
1240  _log(SHIP__HEAT, "%s dissipated %.2f heat points from the %s rack this tic. was %.1f, is %.1f, t = %.3f", \
1241  name(), newHeat, rack.c_str(), heat, (heat - newHeat), t);
1242 
1243  return newHeat;
1244 }
1245 
1247 {
1248  // not used yet
1249 }
1250 
1251 /*
1252  * AttrHeatDamage = 1211,
1253  * AttrHeatDamageBonus = 1213, // module attrib (float x/100 = %)
1254  * AttrHeatGenerationMultiplier = 1224, // ship attrib
1255  * AttrThermodynamicsHeatDamage = 1229, // skill attrib
1256  * AttrHeatDamageMultiplier = 1485, // system beacon effect
1257 */
1258 
1259 /*
1260 Slt Att Damage chance multiplier at distance from overheated module (in %)
1261  1 2 3 4 5 6 7
1262 1 0.00 0.10
1263 2 0.25 0.25
1264 3 0.50 0.50 0.25
1265 4 0.63 0.63 0.40 0.25
1266 5 0.71 0.71 0.50 0.36 0.25
1267 6 0.76 0.76 0.58 0.44 0.33 0.25
1268 7 0.79 0.79 0.62 0.49 0.39 0.31 0.24
1269 8 0.82 0.82 0.67 0.55 0.45 0.37 0.30 0.25
1270 */
1271 //Cycles to burnout = total module HP/ (hp heat damage per cycle - (hp heat damage per cycle*thermodynamics level*5/100))
1273 {
1274  if (pMod->IsLinked()) // linked slaves will contribute to heat calculation, but not individually.
1275  if (!pMod->IsMaster()) // heat is calculated by master and multiplied by #linked modules
1276  return;
1277 
1278  // check ship's current bank heat to determine chance for pMod to take heat damage.
1279  // damage to other modules based on table above.
1280  float curHeat(0.0f), damChance(0.0f);
1281  if (pMod->isHighPower()) {
1282  curHeat = GetAttribute(AttrHeatHi).get_float();
1284  } else if (pMod->isMediumPower()) {
1285  curHeat = GetAttribute(AttrHeatMed).get_float();
1287  } else if (pMod->isLowPower()) {
1288  curHeat = GetAttribute(AttrHeatLow).get_float();
1290  }
1291 
1292  std::vector<uint32> modVec;
1293  // if this module is grouped, all modules will take same damage.
1294  if (pMod->IsLinked()) {
1295  // not used yet
1296  } else {
1297  // module not linked. continue with default heat damage calc's
1298  // determine position and get adjacent modules
1299  uint8 flag = pMod->flag();
1300 
1301  // determine modules to damage and add to list
1302  uint32 moduleID(0);
1303 
1304  //modVec.push_back(moduleID);
1305  }
1306 
1307  for (auto cur : modVec)
1308  DamageModule(cur);
1309 }
1310 
1312 {
1313  UnlinkAllWeapons();
1314 
1316  if (sDataMgr.IsStation(locationID()))
1317  flag = flagHangar;
1318 
1319  std::vector<InventoryItemRef> moduleList;
1321  for (auto cur : moduleList) {
1322  m_ModuleManager->UnfitModule(cur->itemID());
1323  cur->Move(locationID(), flag, true);
1324  }
1325 }
1326 
1328 {
1329  std::map<uint32, InventoryItemRef> invMap;
1330  pInventory->GetInventoryMap( invMap );
1331  for (auto cur : invMap )
1332  cur.second->Move(locationID(), flagHangar, true);
1333 }
1334 
1336  // loop thru modules and deactivate any type of miner
1338  // tell drones cargo is full. this will command mining types to return and orbit
1339  // drones->return();
1340 }
1341 
1342 void ShipItem::GetLinkedWeaponMods( EVEItemFlags flag, std::vector<GenericModule*> &modules ) {
1343  GenericModule* pMod = m_ModuleManager->GetModule(flag);
1344  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod);
1345  if (itr != m_linkedWeapons.end()) {
1346  modules.push_back(pMod);
1347  for (auto cur : itr->second)
1348  modules.push_back(cur);
1349  } else {
1350  // this module isnt master... loop thru all links and see if we can find it
1351  for (auto cur : m_linkedWeapons) {
1352  std::list<GenericModule*>::iterator itr2 = cur.second.begin(), end = cur.second.end();
1353  while (itr2 != end) {
1354  if ((*itr2) == pMod) {
1355  GetLinkedWeaponMods(cur.first->flag(), modules);
1356  return;
1357  }
1358  ++itr2;
1359  }
1360  }
1361  }
1362 }
1363 
1364 // only called from dogma call. can throw
1365 void ShipItem::LinkWeapon(uint32 masterID, uint32 slaveID)
1366 {
1367  if (masterID == slaveID)
1368  return;
1369  GenericModule* pMod1 = m_ModuleManager->GetModule(masterID);
1370  GenericModule* pMod2 = m_ModuleManager->GetModule(slaveID);
1371  LinkWeapon(pMod1, pMod2);
1372 
1373  SaveWeaponGroups();
1374 }
1375 
1377 {
1378  if ((pMaster == nullptr) or (pSlave == nullptr))
1379  return; // make error here?
1380  if (pMaster == pSlave)
1381  return; // make error here?
1382  if ((pMaster->IsLoaded()) or (pSlave->IsLoaded()))
1383  throw UserError ("CantLinkAmmoInWeapon");
1384  if ((pMaster->IsActive()) or (pSlave->IsActive()))
1385  throw UserError ("CantLinkModuleActive");
1386  if ((pMaster->IsDamaged()) or (pSlave->IsDamaged()))
1387  throw UserError ("CantLinkModuleDamaged");
1388  if ((pMaster->IsLoading()) or (pSlave->IsLoading()))
1389  throw UserError ("CantLinkModuleLoading");
1390  if ((!pMaster->isOnline()) or (!pSlave->isOnline()))
1391  throw UserError ("CantLinkModuleNotOnline");
1392 
1393  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMaster);
1394  if (itr == m_linkedWeapons.end()) {
1395  std::list<GenericModule*> slaves;
1396  slaves.push_back(pSlave);
1397  m_linkedWeapons[pMaster] = slaves;
1398  pMaster->SetLinked(true);
1399  pMaster->SetLinkMaster(true);
1400  } else {
1401  itr->second.push_back(pSlave);
1402  }
1403  pSlave->SetLinked(true);
1404 }
1405 
1407 {
1408  _log(MODULE__ERROR, "MergeModuleGroups() called by %s(%u). It still needs to be written.", name(), itemID());
1409 }
1410 
1411 void ShipItem::PeelAndLink(uint32 masterID, uint32 slaveID)
1412 {
1413  _log(MODULE__ERROR, "PeelAndLink() called by %s(%u). It still needs to be written.", name(), itemID());
1414 }
1415 
1417 {
1418  std::list< GenericModule* > weaponList;
1419  m_ModuleManager->GetWeapons(weaponList);
1420 
1421  // remove current links
1422  for (auto cur : weaponList) {
1423  if (sConfig.server.UnloadOnLinkAll)
1425  cur->SetLinked(false);
1426  cur->SetLinkMaster(false);
1427  }
1428  m_linkedWeapons.clear();
1429 
1430  LinkWeaponLoop(weaponList);
1431 
1432  // remove empty masters from map
1433  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.begin();
1434  while (itr != m_linkedWeapons.end()) {
1435  if (itr->second.empty()) {
1436  if (is_log_enabled(MODULE__INFO))
1437  _log(MODULE__INFO, "ShipItem::LinkAllWeapons() - %s(%s) has empty link list. Removing.", \
1438  itr->first->GetSelf()->name(), sDataMgr.GetFlagName(itr->first->flag()));
1439  itr = m_linkedWeapons.erase(itr);
1440  } else {
1441  ++itr;
1442  }
1443  }
1444 
1445  SaveWeaponGroups();
1446 }
1447 
1448 void ShipItem::LinkWeaponLoop(std::list<GenericModule*>& weaponList)
1449 {
1450  double start = GetTimeUSeconds();
1451  GenericModule* master(nullptr);
1452  std::list< GenericModule*>::iterator itr = weaponList.begin();
1453  while (itr != weaponList.end()) {
1454  if ((*itr)->IsLoaded() or (*itr)->IsLoading()) {
1455  if (is_log_enabled(MODULE__INFO))
1456  _log(MODULE__INFO, "ShipItem::LinkWeaponLoop() - %s(%s-%u) IsLoaded. Skipping.", \
1457  (*itr)->GetSelf()->name(), sDataMgr.GetFlagName((*itr)->flag()), (*itr)->itemID());
1458  m_pilot->SendErrorMsg("You cannot group the %s while loaded with %s", (*itr)->GetSelf()->name(), (*itr)->GetLoadedChargeRef()->name());
1459  itr = weaponList.erase(itr);
1460  } else if (master == nullptr) {
1461  // lets check if this module will match a master already in list before making new master...
1462  bool match(false);
1463  for (auto item : m_linkedWeapons)
1464  if (item.first->typeID() == (*itr)->typeID()) {
1465  //master = item.first;
1466  if (is_log_enabled(MODULE__INFO))
1467  _log(MODULE__INFO, "ShipItem::LinkWeaponLoop() -(null master) %s(%s-%u) matches list master %s(%s-%u). Adding.", \
1468  (*itr)->GetSelf()->name(), sDataMgr.GetFlagName((*itr)->flag()), (*itr)->itemID(), \
1469  item.first->GetSelf()->name(), sDataMgr.GetFlagName(item.first->flag()), item.first->itemID());
1470  LinkWeapon(item.first, (*itr));
1471  itr = weaponList.erase(itr);
1472  match = true;
1473  break;
1474  }
1475  if (match)
1476  continue;
1477  // didnt match, or list empty. make new master.
1478  master = (*itr);
1479  if (is_log_enabled(MODULE__INFO))
1480  _log(MODULE__INFO, "ShipItem::LinkWeaponLoop() - Setting %s(%s-%u) to master.",\
1481  (*itr)->GetSelf()->name(), sDataMgr.GetFlagName((*itr)->flag()), (*itr)->itemID());
1482  // set blank list for this master.
1483  std::list<GenericModule*> slaves;
1484  m_linkedWeapons[master] = slaves;
1485  itr = weaponList.erase(itr);
1486  } else {
1487  if (master->typeID() == (*itr)->typeID()) { // this item can be slave
1488  if (is_log_enabled(MODULE__INFO))
1489  _log(MODULE__INFO, "ShipItem::LinkWeaponLoop() - %s(%s-%u) matches master %s(%s-%u). Adding.", \
1490  (*itr)->GetSelf()->name(), sDataMgr.GetFlagName((*itr)->flag()), (*itr)->itemID(), \
1491  master->GetSelf()->name(), sDataMgr.GetFlagName(master->flag()), master->itemID());
1492  LinkWeapon(master, (*itr));
1493  itr = weaponList.erase(itr);
1494  } else {
1495  for (auto item : m_linkedWeapons)
1496  if (item.first->typeID() == (*itr)->typeID()) {
1497  //master = item.first;
1498  if (is_log_enabled(MODULE__INFO))
1499  _log(MODULE__INFO, "ShipItem::LinkWeaponLoop() - %s(%s-%u) matches list master %s(%s-%u). Adding.", \
1500  (*itr)->GetSelf()->name(), sDataMgr.GetFlagName((*itr)->flag()), (*itr)->itemID(), \
1501  item.first->GetSelf()->name(), sDataMgr.GetFlagName(item.first->flag()), item.first->itemID());
1502  LinkWeapon(item.first, (*itr));
1503  itr = weaponList.erase(itr);
1504  break;
1505  }
1506  master = nullptr;
1507  }
1508  }
1509  }
1510  if (is_log_enabled(MODULE__INFO))
1511  _log(MODULE__INFO, "ShipItem::LinkWeaponLoop() - Completed loop in %.3fus.", GetTimeUSeconds() - start);
1512 }
1513 
1514 /*
1515  * {'messageKey': 'CantUngroupModuleActive', 'dataID': 17874986, 'suppressable': False, 'bodyID': 256339, 'messageType': 'hint', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 3540}
1516  * (256339, `You cannot ungroup active modules, please deactivate them first.`)
1517  * {'messageKey': 'CantUngroupModuleLoading', 'dataID': 17874989, 'suppressable': False, 'bodyID': 256340, 'messageType': 'hint', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 3541}
1518  * (256340, `You can't ungroup weapons while they are being loaded with charges.`)
1519  * {'messageKey': 'CantUnlinkModuleActive', 'dataID': 17878129, 'suppressable': False, 'bodyID': 257511, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 2679}
1520  * (257511, `You cannot ungroup active modules, please deactivate them first.`)
1521  */
1523 {
1524  GenericModule* pMod1(m_ModuleManager->GetModule(moduleID));
1525  if (pMod1 == nullptr)
1526  return 0; // make error here?
1527 
1528  if (pMod1->IsActive()) {
1529  m_pilot->SendNotifyMsg("You cannot ungroup active modules, please deactivate them first.");
1530  return 0;
1531  }
1532  if (pMod1->IsLoading()) {
1533  m_pilot->SendNotifyMsg("You cannot ungroup weapons while they are being loaded with charges.");
1534  return 0;
1535  }
1536  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod1);
1537  if (itr == m_linkedWeapons.end())
1538  return 0;
1539 
1540  // weird shit here, but this works...
1541 
1542  // get first linked moduleID
1543  uint32 slaveID(itr->second.front()->itemID());
1544  // delete group
1545  UnlinkGroup(moduleID);
1546  LinkWeapon(moduleID, slaveID);
1547  // make packet for master and first slave (slaveID)
1548  PyList* slaves = new PyList();
1549  slaves->AddItem(new PyInt(slaveID));
1550  PyDict* result = new PyDict();
1551  result->SetItem(new PyInt(moduleID), slaves);
1552  PyTuple* tuple = new PyTuple(3);
1553  tuple->SetItem(0, new PyString("OnWeaponBanksChanged"));
1554  tuple->SetItem(1, new PyInt(m_itemID));
1555  tuple->SetItem(2, result); //GetLinkedWeapons()
1556  // send 'new' group data to client
1557  m_pilot->QueueDestinyEvent(&tuple);
1558  // send immediately (otherwise it will wait until after this call returns, which negates this hack
1559  //m_pilot->FlushQueue();
1560 
1561  // return slaveID, which client will use to delete it's map and continue processing
1562  return slaveID;
1563 }
1564 
1565 // only called from dogma call. can throw
1566 void ShipItem::UnlinkWeapon(uint32 masterID, uint32 slaveID)
1567 {
1568  if (masterID == slaveID)
1569  return;
1570  GenericModule* pMod1(m_ModuleManager->GetModule(masterID));
1571  GenericModule* pMod2(m_ModuleManager->GetModule(slaveID));
1572  if ((pMod1 == nullptr) or (pMod2 == nullptr))
1573  return; // make error here?
1574 
1575  // if master is loading or active, then whole group is
1576  if (pMod1->IsActive())
1577  throw UserError ("CantUngroupModuleActive");
1578  if (pMod1->IsLoading())
1579  throw UserError ("CantUngroupModuleLoading");
1580 
1581  pMod2->SetLinked(false);
1582 
1583  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod1);
1584  if (itr != m_linkedWeapons.end()) {
1585  std::list<GenericModule*>::iterator itr2 = itr->second.begin();
1586  while (itr2 != itr->second.end()) {
1587  if ((*itr2) == pMod2) {
1588  itr2 = itr->second.erase(itr2);
1589  if (itr->second.empty()) {
1590  pMod1->SetLinked(false);
1591  pMod1->SetLinkMaster(false);
1592  m_linkedWeapons.erase(itr);
1593  }
1594  return;
1595  }
1596  ++itr2;
1597  }
1598  }
1599 }
1600 
1601 // only called from dogma call. can throw
1602 void ShipItem::UnlinkGroup(uint32 memberID, bool update/*false*/)
1603 {
1604  GenericModule* pMod1(m_ModuleManager->GetModule(memberID));
1605  if (pMod1 == nullptr)
1606  return; // make error here?
1607 
1608  // if master is loading or active, then whole group is
1609  if (pMod1->IsActive())
1610  throw UserError ("CantUngroupModuleActive");
1611  if (pMod1->IsLoading())
1612  throw UserError ("CantUngroupModuleLoading");
1613 
1614  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod1);
1615  if (itr != m_linkedWeapons.end()) {
1616  pMod1->SetLinked(false);
1617  pMod1->SetLinkMaster(false);
1618  std::list<GenericModule*>::iterator itr2 = itr->second.begin();
1619  while (itr2 != itr->second.end()) {
1620  (*itr2)->SetLinked(false);
1621  itr2 = itr->second.erase(itr2);
1622  if (itr->second.empty()) {
1623  m_linkedWeapons.erase(itr);
1624  SaveWeaponGroups();
1625  if (update) {
1626  PyTuple* tuple = new PyTuple(3);
1627  tuple->SetItem(0, new PyString("OnWeaponGroupDestroyed"));
1628  tuple->SetItem(1, new PyInt(m_itemID));
1629  tuple->SetItem(2, new PyInt(memberID));
1630  m_pilot->QueueDestinyEvent(&tuple);
1631  }
1632  return;
1633  }
1634  }
1635  } else {
1636  // this module isnt master... loop thru all links to see if we can find it
1637  for (auto cur : m_linkedWeapons) {
1638  std::list<GenericModule*>::iterator itr2 = cur.second.begin();
1639  while (itr2 != cur.second.end()) {
1640  if ((*itr2) == pMod1) {
1641  UnlinkGroup(cur.first->itemID(), update);
1642  return;
1643  }
1644  ++itr2;
1645  }
1646  }
1647  }
1648 }
1649 
1650 // called from here and dogma call. can throw
1652 {
1653  std::list< GenericModule* > weaponList;
1654  m_ModuleManager->GetWeapons(weaponList);
1655  for (auto cur : weaponList) {
1656  if (cur->IsActive())
1657  throw UserError ("CantUngroupModuleActive");
1658  if (cur->IsLoading())
1659  throw UserError ("CantUngroupModuleLoading");
1660 
1661  cur->SetLinked(false);
1662  cur->SetLinkMaster(false);
1663  }
1664  m_linkedWeapons.clear();
1666 }
1667 
1669 {
1670  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod);
1671  if (itr == m_linkedWeapons.end())
1672  return 1;
1673  return itr->second.size() + 1;
1674 }
1675 
1677 {
1678  uint8 count(1);
1679  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod);
1680  if (itr != m_linkedWeapons.end()) {
1681  std::list<GenericModule*>::iterator itr2 = itr->second.begin(), end = itr->second.end();
1682  while (itr2 != end) {
1683  if ((*itr2)->IsLoaded())
1684  ++count;
1685  ++itr2;
1686  }
1687  }
1688  return count;
1689 }
1690 
1692 {
1693  if (m_linkedWeapons.empty())
1694  return PyStatic.NewNone();
1695 
1696  PyDict* result = new PyDict();
1697  for (auto cur : m_linkedWeapons) {
1698  PyList* slaves = new PyList();
1699  for (auto slave : cur.second)
1700  slaves->AddItem(new PyInt(slave->itemID()));
1701  result->SetItem(new PyInt(cur.first->itemID()), slaves);
1702  }
1703 
1704  if (is_log_enabled(MODULE__MESSAGE)) {
1705  _log(MODULE__MESSAGE, "GetLinkedWeapons()");
1706  result->Dump(MODULE__MESSAGE, " ");
1707  }
1708  return result;
1709 }
1710 
1712 {
1713  if (pMod->IsMaster()) {
1714  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMod);
1715  if (itr != m_linkedWeapons.end())
1716  for (auto cur : itr->second)
1717  cur->Offline();
1718  } else {
1719  // this module isnt master... loop thru all links to see if we can find it
1720  for (auto cur : m_linkedWeapons) {
1721  std::list<GenericModule*>::iterator itr = cur.second.begin();
1722  while (itr != cur.second.end()) {
1723  if ((*itr) == pMod) {
1724  OfflineGroup(cur.first);
1725  return;
1726  }
1727  ++itr;
1728  }
1729  }
1730  }
1731 }
1732 
1734 {
1735  std::multimap< uint32, uint32 > data;
1736  data.clear();
1737  if (!m_linkedWeapons.empty())
1738  for (auto cur : m_linkedWeapons)
1739  for (auto slave : cur.second)
1740  data.emplace(cur.first->itemID(), slave->itemID());
1741 
1743 }
1744 
1746 {
1747  // NOTE: there probably isnt a pilot at this point, so no sending of errors on load.
1748  if (m_ModuleManager == nullptr) {
1749  if (m_pilot != nullptr)
1750  m_pilot->SendErrorMsg("There was an error loading your weapon groups. Ref: ServerError 06071");
1751  return;
1752  }
1753  DBQueryResult* res = new DBQueryResult();
1755 
1756  bool error(false);
1757  GenericModule* pMaster(nullptr);
1758  GenericModule* pSlave(nullptr);
1759  DBResultRow row;
1760  // this is gonna be slow as shit...i dont like this, but best way to do it.
1761  while (res->GetRow(row)) {
1762  //SELECT masterID, slaveID FROM shipWeaponGroups
1763  pMaster = m_ModuleManager->GetModule(row.GetInt(0));
1764  pSlave = m_ModuleManager->GetModule(row.GetInt(1));
1765  if ((pMaster == nullptr) or (pSlave == nullptr)) {
1766  error = true;
1767  continue;
1768  }
1769  //LinkWeapon(pMaster, pSlave); <<<--- this will throw. DO NOT use here.
1770  std::map<GenericModule*, std::list<GenericModule*>>::iterator itr = m_linkedWeapons.find(pMaster);
1771  if (itr == m_linkedWeapons.end()) {
1772  std::list<GenericModule*> slaves;
1773  slaves.push_back(pSlave);
1774  m_linkedWeapons[pMaster] = slaves;
1775  } else {
1776  itr->second.push_back(pSlave);
1777  }
1778  pMaster->SetLinked(true);
1779  pMaster->SetLinkMaster(true);
1780  pSlave->SetLinked(true);
1781  }
1782 
1783  if (error) {
1784  UnlinkAllWeapons();
1785  if (m_pilot != nullptr)
1786  m_pilot->SendErrorMsg("There was an error loading a weapon group master. Ref: ServerError 06123");
1787  }
1788 
1789  SafeDelete(res);
1790 }
1791 /* End new Module Manager Interface */
1792 
1793 // new effects system. wip
1794 void ShipItem::ProcessEffects(bool add/*false*/, bool update/*false*/)
1795 {
1796  _log(EFFECTS__TRACE, "ShipItem::ProcessEffects()");
1797  double start = GetTimeMSeconds();
1798  /*
1799  Effects processing order...
1800  Skills //char effect
1801  Implants //char effect
1802  Boosters //char effect
1803  Ship //ship effect
1804  Subsystem //module effect
1805  Rigs //module effect
1806  Low //module effect
1807  Mid //module effect
1808  Hi //module effect
1809  */
1810  if (add) {
1811  m_pilot->GetChar()->ProcessEffects(this);
1812  ProcessShipEffects(update);
1813  } else {
1814  ClearModifiers();
1815  pAttributeMap->SaveShipState(); // save ship damage as it's removed on next call
1816  ResetAttributes();
1819  std::vector< InventoryItemRef > modVec;
1821  for (auto cur : modVec)
1822  cur->ResetAttributes();
1823  std::map<EVEItemFlags, InventoryItemRef> charges;
1825  for (auto cur : charges)
1826  cur.second->ResetAttributes();
1827 
1828  // do we remove fx here? nah, we've reset everything at this point.
1829  }
1830 
1831  _log(EFFECTS__DEBUG, "ShipItem::ProcessEffects() - effects processed and applied in %.3fms", (GetTimeMSeconds() - start));
1832 }
1833 
1834 void ShipItem::ProcessShipEffects(bool update/*false*/)
1835 {
1836  _log(EFFECTS__TRACE, "ShipItem::ProcessShipEffects()");
1837  for (auto it : type().m_stateFxMap) {
1838  fxData data = fxData();
1839  data.action = FX::Action::Invalid;
1840  data.srcRef = static_cast<InventoryItemRef>(this);
1841  sFxProc.ParseExpression(this, sFxDataMgr.GetExpression(it.second.preExpression), data);
1842  }
1843  // apply processed ship effects
1844  sFxProc.ApplyEffects(this, m_pilot->GetChar().get(), this, update);
1845  //ClearModifiers();
1846 
1847  if (m_isUndocking) {
1848  // online modules sent from client (these are onlined in fit window while docked)
1850  m_onlineModuleVec.clear();
1851  //FailedToOnlineModulesOnUndock
1852  } else {
1853  // this will set module to last saved online state in the case of BoardShip() and Login()
1855  }
1856 }
1857 
1859 {
1860  _log(EFFECTS__TRACE, "ShipItem::ClearModuleModifiers()");
1861  //m_ModuleManager->OfflineAll();
1862  std::vector< InventoryItemRef > modVec;
1864  for (auto cur : modVec)
1865  cur->ClearModifiers();
1866  std::map<EVEItemFlags, InventoryItemRef> charges;
1868  for (auto cur : charges)
1869  cur.second->ClearModifiers();
1870 }
1871 
1873  _log(EFFECTS__TRACE, "ShipItem::ResetEffects()");
1874  double start = GetTimeMSeconds();
1875 
1877 
1878  // reset attributes on char, ship, all modules and charges
1879  pAttributeMap->SaveShipState(); // save ship damage as it's removed on next call
1880  ResetAttributes();
1882  std::vector< InventoryItemRef > modVec;
1884  for (auto cur : modVec)
1885  cur->ResetAttributes();
1886  std::map<EVEItemFlags, InventoryItemRef> charges;
1888  for (auto cur : charges)
1889  cur.second->ResetAttributes();
1890 
1891  ProcessEffects(true, true/*sDataMgr.IsSolarSystem(locationID())*/);
1892  _log(EFFECTS__DEBUG, "ShipItem::ResetEffects() - Effects reset in %.3fms", (GetTimeMSeconds() - start));
1893 }
1894 
1896  // "Offline" modules (see notes in GM::Online and GM::Offline
1898  // clear fx maps before undock
1899  ProcessEffects();
1900 }
1901 
1903 {
1904  /* ship dna is shorthand notation to describe a ship and it's fittings purely thru the use of typeIDs and quantities
1905  *
1906  * the format is as follows:
1907  * <shipTypeID>:
1908  * <subsystemID>:
1909  * <moduleType-Highslot>;<quantity>:
1910  * <moduleType-Midslot>;<quantity>:
1911  * <moduleType-Lowslot>;<quantity>:
1912  * <moduleType-Rigslot>;<quantity>:
1913  * <chargeType>;<quantity>:
1914  * <droneType>;<quantity>
1915  *
1916  * Condensed version:
1917  * Ship:Subsystem:Highs:Mids:Lows:Rigs:Charges:Drones
1918  *
1919  * [PyString "<url=fitting:24698:3841;2:2531;1:19812;1:23527;1:2410;7:1422;4:2547;1:31802;3:2301;1:2454;5::>Anchor</url>"]
1920  *
1921  * current code returns this:
1922  * "587:8863;1:8863;1:8863;1:499;1:578;1:1798;1:6485;1:2046;1:8325;1:31788;1:31800;1:31788;1::"
1923  * need to figure out how to group modules for correct condensed counts
1924  */
1925  if (typeID() == EVEDB::invTypes::Capsule) {
1926  std::stringstream dna;
1927  dna << typeID() << ":";
1928  _log(SHIP__MESSAGE, "ShipDNA has compiled DNA of \"%s\" for %s(%u) ", dna.str().c_str(), name(), itemID());
1929  return dna.str();
1930  }
1931 
1932  /* find and encode the module typeIDs */
1933  std::stringstream modHi, modMid, modLow, subSys, modRig, charges, drones;
1934 
1935  std::vector<InventoryItemRef> moduleList;
1937 
1939  for (auto cur : moduleList) {
1940  if (IsRigSlot(cur->flag())) {
1941  modRig << cur->typeID() << ";" << cur->quantity() << ":";
1942  } else if (IsHiSlot(cur->flag())) {
1943  modHi << cur->typeID() << ";" << cur->quantity() << ":";
1944  } else if (IsMidSlot(cur->flag())) {
1945  modMid << cur->typeID() << ";" << cur->quantity() << ":";
1946  } else if (IsLowSlot(cur->flag())) {
1947  modLow << cur->typeID() << ";" << cur->quantity() << ":";
1948  } else if (IsSubSystem(cur->flag())) {
1949  subSys << cur->typeID() << ":";
1950  } else {
1951  ; // error?
1952  }
1953  }
1954 
1955  std::map<EVEItemFlags, InventoryItemRef> chargeList;
1956  m_ModuleManager->GetLoadedCharges(chargeList);
1957  for (auto cur : chargeList)
1958  charges << cur.second->typeID() << ";" << cur.second->quantity() << ":";
1959 
1960  /* not sure how to get drones yet. will work on later */
1961  drones << ":";
1962 
1963  /* build the dna stream */
1964  std::stringstream dna;
1965  dna << typeID() << ":";
1966  dna << subSys.str() << modHi.str() << modMid.str() << modLow.str() << modRig.str() << charges.str() << drones.str();
1967 
1968  _log(SHIP__MESSAGE, "ShipDNA has compiled \"%s\" for %s(%u) ", dna.str().c_str(), name(), itemID());
1969  return dna.str();
1970 }
1971 
1972 void ShipItem::VerifyHoldType(EVEItemFlags flag, InventoryItemRef iRef, Client* pClient/*nullptr*/)
1973 {
1974  // if *this ship isnt active, it wont have a pilot to send errors to. test and set as needed.
1975  // to fix this, set client to character calling the move
1976  if (pClient == nullptr) {
1977  if (m_pilot == nullptr)
1978  return;
1979  pClient = m_pilot;
1980  }
1981 
1982  switch (flag) {
1983  case flagCargoHold:
1984  // everything can be stored in general cargo
1985  // update this later to disallow specialized items?
1986  return;
1987  case flagDroneBay: {
1988  if (iRef->categoryID() != EVEDB::invCategories::Drone) {
1989  throw CustomError ("%s cannot be stowed in the Drone Bay", sDataMgr.GetGroupName(iRef->groupID()));
1990  }
1992  // these can only carry fighters and fighter/bombers in drone bay. enforce that here.
1993  if ((iRef->groupID() != EVEDB::invGroups::Fighter_Bomber)
1994  and (iRef->groupID() != EVEDB::invGroups::Fighter_Drone)) {
1995  throw CustomError ("The %s can only carry fighter drones in it's Drone Bay. The %s is not allowed.", name(), iRef->name());
1996  }
1997  }
1998  } break;
1999  case flagShipHangar: { //AttrShipMaintenanceBayCapacity
2001  throw CustomError ("Your %s has no ship maintenance bay.", name());
2002  }
2004  if ((iRef->groupID() != EVEDB::invGroups::MiningBarge)
2005  and (iRef->groupID() != EVEDB::invGroups::Exhumer)
2006  and (iRef->groupID() != EVEDB::invGroups::Industrial)
2007  and (iRef->groupID() != EVEDB::invGroups::TransportShip)
2008  and (iRef->groupID() != EVEDB::invGroups::Freighter)
2011  throw CustomError ("Only indy ships may be placed into the Rorqual's ship hold.");
2012  }
2013  if (iRef->categoryID() != EVEDB::invCategories::Ship) {
2014  throw CustomError ("Only ships may be placed into the maintenance bay.");
2015  }
2016  } break;
2017  case flagFuelBay: { // AttrFuelBayCapacity
2018  if ((iRef->groupID() != EVEDB::invGroups::FuelBlock)
2019  and (iRef->groupID() != EVEDB::invGroups::Ice_Product)) {
2020  throw CustomError ("Only fuel types may be stored in the fuel bay.");
2021  }
2022  } break;
2023  case flagOreHold: {
2024  if (iRef->categoryID() != EVEDB::invCategories::Asteroid) {
2025  throw CustomError ("Only mined ore may be stored in the ore hold.");
2026  }
2027  } break;
2028  case flagGasHold: {
2029  if (iRef->groupID() != EVEDB::invGroups::Gas_Isotopes) {
2030  throw CustomError ("Only gas products may be stored in the gas hold.");
2031  }
2032  } break;
2033  case flagMineralHold: {
2034  if (iRef->groupID() != EVEDB::invGroups::Mineral) {
2035  throw CustomError ("Only refined minerals may be placed into the mineral hold.");
2036  }
2037  } break;
2038  case flagSalvageHold: {
2040  throw CustomError ("Only salvaged materials may be placed into the salvage bay.");
2041  }
2042  } break;
2043  // not sure if all of these flag* are used. if not, *may* update dgmData to add them....later.
2044  case flagShipHold: {
2045  if (iRef->categoryID() != EVEDB::invCategories::Ship) {
2046  throw CustomError ("Only ships may be placed into the ship hold.");
2047  }
2048  } break;
2049 
2051  case flagSmallShipHold: {
2052  if (iRef->categoryID() != EVEDB::invCategories::Ship) {
2053  throw CustomError ("Only small ships may be placed into the ship's small ship hold.");
2054  }
2055  } break;
2056  case flagMediumShipHold: {
2057  if (iRef->categoryID() != EVEDB::invCategories::Ship) {
2058  throw CustomError ("Only medium ships may be placed into the ship's medium ship hold.");
2059  }
2060  } break;
2061  case flagLargeShipHold: {
2062  if (iRef->categoryID() != EVEDB::invCategories::Ship) {
2063  throw CustomError ("Only large ships may be placed into the ship's large ship hold.");
2064  }
2065  } break;
2066  case flagIndustrialShipHold: {
2067  if ((iRef->groupID() != EVEDB::invGroups::MiningBarge)
2068  and (iRef->groupID() != EVEDB::invGroups::Exhumer)
2069  and (iRef->groupID() != EVEDB::invGroups::Industrial)
2070  and (iRef->groupID() != EVEDB::invGroups::TransportShip)
2071  and (iRef->groupID() != EVEDB::invGroups::Freighter)
2074  throw CustomError ("Only indy ships may be placed into the ship's industrial ship hold.");
2075  }
2076  } break;
2077  case flagAmmoHold: {
2078  if ((iRef->groupID() != EVEDB::invGroups::Ammo)
2080  and (iRef->groupID() != EVEDB::invGroups::Mining_Crystal)
2088  and (iRef->groupID() != EVEDB::invGroups::Hybrid_Ammo)) {
2089  throw CustomError ("Only ammunition and crystals may be placed into the ammo bay.");
2090  }
2091  } break;
2092  case flagHangar:
2093  case flagCorpHangar2:
2094  case flagCorpHangar3:
2095  case flagCorpHangar4:
2096  case flagCorpHangar5:
2097  case flagCorpHangar6:
2098  case flagCorpHangar7: { //AttrCorporateHangarCapacity
2100  throw CustomError ("Your %s has no corporate hangars.", name());
2101  }
2102  } break;
2103  default: {
2104  // {'FullPath': u'UI/Messages', 'messageID': 259450, 'label': u'ItemNotHardwareBody'}(u'{[item]itemname.name} cannot be fitted onto a ship. Only hardware modules can be fitted.', None, {u'{[item]itemname.name}': {'conditionalValues': [], 'variableType': 2, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'itemname'}})
2105 
2106  if ((iRef->categoryID() != EVEDB::invCategories::Module)
2107  and (iRef->categoryID() != EVEDB::invCategories::Charge)
2108  and (iRef->categoryID() != EVEDB::invCategories::Subsystem)) {
2109  throw CustomError ("%s cannot be fitted onto a ship. Only hardware modules may be fitted.", iRef->name());
2110  }
2111 
2112  if (IsModuleSlot(flag)) {
2113  if (!Skill::FitModuleSkillCheck(iRef, pClient->GetChar())) {
2114  throw CustomError ("You do not have the required skills to fit this %s. Ref: ServerError 25163.", iRef->name());
2115  }
2116  if (!ValidateItemSpecifics(iRef)) {
2117  throw CustomError ("Your ship cannot equip the %s.<br>The group '%s' is not allowed on your %s.", \
2118  iRef->name(), sDataMgr.GetGroupName(iRef->groupID()), type().name().c_str());
2119  }
2120  if (iRef->categoryID() == EVEDB::invCategories::Charge) {
2121  GenericModule* pMod(m_ModuleManager->GetModule(flag));
2122  if (pMod != nullptr) {
2123  // note: this is also checked in client before calling Load()
2124  if (iRef->HasAttribute(AttrChargeSize))
2125  if (pMod->GetAttribute(AttrChargeSize) != iRef->GetAttribute(AttrChargeSize)) {
2126  sLog.Error("ShipItem::VerifyHoldType", "Charge size %u for %s does not match Module size %u for %s.",\
2127  iRef->GetAttribute(AttrChargeSize).get_uint32(), iRef->name(),\
2128  pMod->GetAttribute(AttrChargeSize).get_uint32(), pMod->GetSelf()->name());
2129  throw CustomError ("Incorrect charge size for this module.");
2130  }
2131  if ((pMod->GetAttribute(AttrChargeGroup1) != iRef->groupID())
2132  and (pMod->GetAttribute(AttrChargeGroup2) != iRef->groupID())
2133  and (pMod->GetAttribute(AttrChargeGroup3) != iRef->groupID())
2134  and (pMod->GetAttribute(AttrChargeGroup4) != iRef->groupID())
2135  and (pMod->GetAttribute(AttrChargeGroup5) != iRef->groupID())) {
2136  throw CustomError ("Incorrect charge type for this module.");
2137  }
2138  // NOTE: Module Manager will check for actual room to load charges and make stack splits, or reject loading altogether
2139  } else {
2140  throw CustomError ("There is no module in %s. Ref: ServerError 25162.", sDataMgr.GetFlagName(flag));
2141  }
2142  }
2143  } else {
2144  sLog.Error("ShipItem::VerifyHoldType", "testing %s to add %u %s of cat %s has reached the end.",
2145  sDataMgr.GetFlagName(flag), iRef->quantity(), iRef->name(), sDataMgr.GetCategoryName(iRef->categoryID()));
2146  throw CustomError ("Internal Server Error. Ref: ServerError 25162.");
2147  }
2148  }
2149  }
2150 }
2151 
2152 // this one is called from GetAllInfo
2154 {
2155  if (!pInventory->LoadContents()) {
2156  _log( INV__ERROR, "%s(%u): Failed to load contents for ShipGetInfo", name(), itemID());
2157  return nullptr;
2158  }
2159 
2160  //first populate the ship...
2161  Rsp_CommonGetInfo_Entry entry;
2162  if (!Populate( entry))
2163  return nullptr;
2164 
2165  PyDict* result = new PyDict();
2166  result->SetItem(new PyInt( itemID()), new PyObject("util.KeyVal", entry.Encode()));
2167 
2168  //get modules and charges
2169  std::vector<InventoryItemRef> equipped;
2173  //encode each one...
2174  for (auto cur : equipped) {
2175  Rsp_CommonGetInfo_Entry entry2;
2176  if (cur->Populate(entry2)) {
2177  if (cur->categoryID() == EVEDB::invCategories::Charge) {
2178  PyTuple* tuple = new PyTuple(3);
2179  tuple->SetItem(0, new PyInt(cur->locationID()));
2180  tuple->SetItem(1, new PyInt(cur->flag()));
2181  tuple->SetItem(2, new PyInt(cur->typeID()));
2182  result->SetItem(tuple, new PyObject("util.KeyVal", entry2.Encode()));
2183  } else {
2184  result->SetItem(new PyInt(cur->itemID()), new PyObject("util.KeyVal", entry2.Encode()));
2185  }
2186  } else {
2187  _log( SHIP__ERROR, "%s(%u): Failed to Populate() %s(%u) for ShipGetInfo", \
2188  name(), itemID(), cur->name(), cur->itemID());
2189  }
2190  }
2191 
2192  if (is_log_enabled(SHIP__INFO)) {
2193  _log(SHIP__INFO, "ShipItem::GetShipInfo() decoded:");
2194  result->Dump(SHIP__INFO, " ");
2195  }
2196  return result;
2197 }
2198 
2200  if (!pInventory->ContentsLoaded()) {
2201  if (!pInventory->LoadContents()) {
2202  _log(INV__ERROR, "%s(%u): Failed to load contents for GetShipState", name(), itemID());
2203  return nullptr;
2204  }
2205  }
2206  // Create new dictionary for shipState:
2207  PyDict *result = new PyDict();
2208  // Create entry for ShipItem itself:
2209  result->SetItem(new PyInt(itemID()), GetItemStatusRow());
2210  // Check for and Create entry for pilot:
2211  InventoryItemRef iRefPilot(nullptr);
2212  if (pInventory->GetSingleItemByFlag(flagPilot, iRefPilot))
2213  result->SetItem(new PyInt(iRefPilot->itemID()), iRefPilot->GetItemStatusRow());
2214 
2215  // Create entries for ALL modules, rigs, and subsystems present on ship:
2216  std::vector<InventoryItemRef> moduleList;
2218  for (auto cur : moduleList)
2219  result->SetItem(new PyInt(cur->itemID()), cur->GetItemStatusRow());
2220 
2221  return result;
2222 }
2223 
2225  if (!pInventory->ContentsLoaded()) {
2226  if (!pInventory->LoadContents()) {
2227  _log(INV__ERROR, "%s(%u): Failed to load contents for GetShipState", name(), itemID());
2228  return nullptr;
2229  }
2230  }
2231 
2232  /* get list of all charges loaded in modules */
2233  std::map< EVEItemFlags, InventoryItemRef > charges;
2235 
2236  PyDict *result = new PyDict();
2237  if (charges.empty())
2238  return result;
2239 
2240  // Create entries in "shipState" dictionary for loaded charges on ship:
2241  for (auto cur : charges)
2242  result->SetItem(new PyInt((uint16)cur.first), cur.second->GetChargeStatusRow(itemID()));
2243 
2244  return result;
2245 }
2246 
2248  if (!pInventory->LoadContents()) {
2249  _log(INV__ERROR, "%s(%u): Failed to load contents for ShipGetModuleList", name(), itemID());
2250  return nullptr;
2251  }
2252 
2253  PyList* result = new PyList();
2254  // Create entries in "onslimitemchange" modules list for ALL modules, rigs, and subsystems present on ship:
2255  std::vector<InventoryItemRef> moduleList;
2257  for (auto cur : moduleList) {
2258  PyTuple* module = new PyTuple(2);
2259  module->SetItem(0, new PyInt(cur->typeID()));
2260  module->SetItem(1, new PyInt(cur->itemID()));
2261  result->AddItem(module);
2262  }
2263 
2264  return result;
2265 }
2266 
2268  bool result = false;
2269  EvilNumber skillTypeID(EvilZero);
2270 
2271  if (HasAttribute(AttrRequiredSkill1, skillTypeID)) {
2273  result = true;
2274  if (HasAttribute(AttrRequiredSkill2, skillTypeID)) {
2276  result = true;
2277  } else {
2278  return false;
2279  }
2280  if (HasAttribute(AttrRequiredSkill3, skillTypeID)) {
2282  result = true;
2283  } else {
2284  return false;
2285  }
2286  if (HasAttribute(AttrRequiredSkill4, skillTypeID)) {
2288  result = true;
2289  } else {
2290  return false;
2291  }
2292  if (HasAttribute(AttrRequiredSkill5, skillTypeID)) {
2294  result = true;
2295  } else {
2296  return false;
2297  }
2298  if (HasAttribute(AttrRequiredSkill6, skillTypeID)) {
2300  result = true;
2301  } else {
2302  return false;
2303  }
2304  }
2305  }
2306  }
2307  }
2308  }
2309  } else {
2310  result = true;
2311  }
2312 
2313  return result;
2314 }
2315 
2317 {
2318  bool result(false);
2319  EvilNumber fitID(0);
2320  uint16 groupID(type().groupID());
2321  // If a ship group restriction is specified, the item must be able to fit to at least one ship group.
2322  _log(SHIP__TRACE, "ShipItem::ValidateItemSpecifics - Beginning the group validation for %s(%u):", iRef->name(), iRef->itemID());
2323  if (iRef->HasAttribute(AttrCanFitShipGroup1, fitID)) {
2324  if (fitID == groupID)
2325  result = true;
2326  if (iRef->HasAttribute(AttrCanFitShipGroup2, fitID)) {
2327  if (fitID == groupID)
2328  result = true;
2329  if (iRef->HasAttribute(AttrCanFitShipGroup3, fitID)) {
2330  if (fitID == groupID)
2331  result = true;
2332  if (iRef->HasAttribute(AttrCanFitShipGroup4, fitID)) {
2333  if (fitID == groupID)
2334  result = true;
2335  if (iRef->HasAttribute(AttrCanFitShipGroup5, fitID)) {
2336  if (fitID == groupID)
2337  result = true;
2338  if (iRef->HasAttribute(AttrCanFitShipGroup6, fitID)) {
2339  if (fitID == groupID)
2340  result = true;
2341  if (iRef->HasAttribute(AttrCanFitShipGroup7, fitID)) {
2342  if (fitID == groupID)
2343  result = true;
2344  if (iRef->HasAttribute(AttrCanFitShipGroup8, fitID)) {
2345  if (fitID == groupID)
2346  result = true;
2347  }
2348  }
2349  }
2350  }
2351  }
2352  }
2353  }
2354  } else {
2355  result = true;
2356  }
2357 
2358  _log(SHIP__TRACE, "ShipItem::ValidateItemSpecifics - Group Validation returning %s.", (result ? "true" : "false"));
2359 
2360  if (result) {
2361  _log(SHIP__TRACE, "ShipItem::ValidateItemSpecifics - Beginning the type validation for %s(%u):", iRef->name(), iRef->itemID());
2362 
2363  uint16 typeID(type().id());
2364  if (iRef->HasAttribute(AttrCanFitShipType1, fitID)) {
2365  result = false;
2366  if (fitID == typeID)
2367  result = true;
2368  if (iRef->HasAttribute(AttrCanFitShipType2, fitID)) {
2369  if (fitID == typeID)
2370  result = true;
2371  if (iRef->HasAttribute(AttrCanFitShipType3, fitID)) {
2372  if (fitID == typeID)
2373  result = true;
2374  if (iRef->HasAttribute(AttrCanFitShipType4, fitID)) {
2375  if (fitID == typeID)
2376  result = true;
2377  }
2378  }
2379  }
2380  }
2381 
2382  _log(SHIP__TRACE, "ShipItem::ValidateItemSpecifics - Type Validation returning %s.", (result ? "true" : "false"));
2383  }
2384 
2385  return result;
2386 }
2387 
2388 
2389 /* DynamicSystemEntity representing ship object in space */
2391 : DynamicSystemEntity(self, services, pSystem),
2392 m_shipRef(ShipItemRef::StaticCast(self)),
2393 m_processTimerTick(SHIP_PROCESS_TICK_MS), //5s
2394 m_processTimer(SHIP_PROCESS_TICK_MS),
2395 m_oldArmor(0),
2396 m_oldShield(0),
2397 m_oldScanRes(0),
2398 m_oldInertia(0.0f),
2399 m_oldTargetRange(0),
2400 m_boosted(false),
2401 m_podShipID(0),
2402 m_allowFleetSMBUsage(false)
2403 {
2404  m_warID = data.factionID;
2405  m_allyID = data.allianceID;
2406  m_corpID = data.corporationID;
2407  m_ownerID = data.ownerID;
2408 
2409  m_boost = BoostData();
2410 
2411  m_towerPass = "";
2413  _log(SHIP__TRACE, "Created ShipSE %p for item %u", this, self->itemID());
2414 }
2415 
2416 float ShipSE::CalculateRechargeRate(float Capacity, float Current, float RechargeTimeMS)
2417 {
2418  // C = Cmax * [ 1 + ( SQRT(C0/Cmax) - 1) * EXP((t0-t1)/tau) ] ^ 2
2419  // dC/dt = (SQRT(C/Cmax) - C/Cmax) * 2 * Cmax / tau
2420  // tau = "Cap Recharge Time" / 5.0
2421 
2422  // prevent divide by zero.
2423  RechargeTimeMS = (RechargeTimeMS < 1 ? 1 : RechargeTimeMS);
2424  Current = (Current < 1 ? 1 : Current);
2425  float Cmax = (Capacity < 1 ? 1 : Capacity);
2426 
2427  // tau = "cap recharge time" / 5.0
2428  float tau = (RechargeTimeMS / 5000.0);
2429  // (2*Cmax) / tau
2430  float Cmax2_tau = ((Cmax * 2) / tau);
2431  float C = Current;
2432  // C / Cmax
2433  float C_Cmax = (C / Cmax);
2434  // sqrt( C / Cmax)
2435  float sC_Cmax = sqrt(C_Cmax);
2436  // charge rate in Gj / sec
2437  return (Cmax2_tau * (sC_Cmax - C_Cmax));
2438 }
2439 
2441  if (m_killed)
2442  return;
2443  /* Enable base call to Process Targeting and Movement */
2445 
2446  // check to see if this is an empty ship, and exit if so.
2447  // we're not worried about recharge and modules for empty ships (segfaults)
2449  if ((m_self.get() == nullptr) or (!m_self->HasPilot()))
2450  return;
2451 
2452  if (m_processTimer.Check()) {
2453  double profileStartTime = GetTimeUSeconds();
2454  // shield
2456  float Capacity = m_self->GetAttribute(AttrShieldCapacity).get_float();
2457  if (Charge < Capacity) {
2458  float newCharge = Charge + ((m_processTimerTick /1000) * CalculateRechargeRate(Capacity, Charge, m_self->GetAttribute(AttrShieldRechargeRate).get_float()));
2459  if (newCharge > Capacity) {
2460  newCharge = Capacity;
2461  } else if ((Capacity - newCharge) < 0.3) {
2462  newCharge = Capacity;
2463  }
2464  m_self->SetAttribute(AttrShieldCharge, newCharge);
2466  _log(SHIP__RECHARGE, "ShipSE::Process(): %s(%u) - New Shield Charge: %f", m_self->GetPilot()->GetName(), m_self->itemID(), newCharge);
2467  }
2468 
2469  // cap
2472  if (Charge < Capacity) {
2473  float newCharge = Charge + ((m_processTimerTick /1000) * CalculateRechargeRate(Capacity, Charge, m_self->GetAttribute(AttrRechargeRate).get_float()));
2474  if (newCharge > Capacity) {
2475  newCharge = Capacity;
2476  } else if ((Capacity - newCharge) < 0.3) {
2477  newCharge = Capacity;
2478  }
2480  _log(SHIP__RECHARGE, "ShipSE::Process(): %s(%u) - New Cap Charge: %f", m_self->GetPilot()->GetName(), m_self->itemID(), newCharge);
2481  }
2482  // profile timer for the ship recharge shit
2483  if (sConfig.debug.UseProfiling)
2484  sProfiler.AddTime(Profile::ship, GetTimeUSeconds() - profileStartTime);
2485 
2486  // proc heat on the 5s cap/shield tic, if enabled
2487  if (sConfig.testing.ShipHeat)
2489  }
2490 
2492 }
2493 
2494 void ShipSE::DamageRandModule(float chance)
2495 {
2496  if (chance == 0)
2497  return;
2498  if (chance > MakeRandomFloat())
2500 }
2501 
2504  return;
2505  std::string reason = "Insurance payment for loss of the ship ";
2506  reason += m_self->itemName();
2510 }
2511 
2513 {
2514  m_system = pSystem;
2515 }
2516 
2517 void ShipSE::SetPilot(Client* pClient) {
2518  m_self->SetPlayer(pClient);
2519  if (pClient == nullptr) {
2520  m_allyID = 0;
2521  m_corpID = 0;
2522  return;
2523  }
2524  // set shipSE data
2525  m_allyID = pClient->GetAllianceID();
2526  m_corpID = pClient->GetCorporationID();
2527 }
2528 
2530 {
2531  if (m_shipRef->HasPilot())
2532  return m_shipRef->GetPilot()->IsInvul();
2533  return false;
2534 }
2535 
2537 {
2538  if (m_shipRef->HasPilot())
2539  return m_shipRef->GetPilot()->IsLogin();
2540  return false;
2541 }
2542 
2544  if (m_targMgr != nullptr) {
2546  m_targMgr->ClearAllTargets(false);
2547  //m_targMgr->OnTarget(nullptr, TargMgr::Mode::Clear, TargMgr::Msg::Docking);
2548  }
2549 
2550  m_shipRef->Dock();
2551 }
2552 
2553 void ShipSE::Jump(bool showCloak) {
2554  if (m_targMgr != nullptr) {
2556  m_targMgr->ClearAllTargets(false);
2557  //m_targMgr->OnTarget(nullptr, TargMgr::Mode::Clear, TargMgr::Msg::Jumping);
2558  }
2559 
2560  m_shipRef->Jump();
2561  m_destiny->Jump(showCloak);
2562 }
2563 
2565  if (m_targMgr != nullptr)
2567 
2568  m_shipRef->Warp();
2569 }
2570 
2572  // target has been unlocked
2574 
2575  m_targMgr->ClearTarget(pSE);
2576  //m_targMgr->OnTarget(pSE, TargMgr::Mode::Lost, TargMgr::Msg::StoppedTargeting);
2577 }
2578 
2580  using namespace Destiny;
2581 
2582  uint8 mode = m_destiny->GetState(); //Ball::Mode::STOP;
2583 /*
2584  NameStruct name;
2585  name.name = GetName();
2586  name.name_len = sizeof(name.name);
2587  */
2588  BallHeader head = BallHeader();
2589  head.entityID = GetID();
2590  head.mode = mode;
2591  head.radius = GetRadius();
2592  head.posX = x();
2593  head.posY = y();
2594  head.posZ = z();
2595  if (m_self->HasPilot()) {
2597  } else {
2598  head.flags = Ball::Flag::IsFree;
2599  }
2600  into.Append( head);
2601  MassSector mass = MassSector();
2602  mass.mass = m_destiny->GetMass();
2603  mass.cloak = (m_destiny->IsCloaked() ? 1 : 0);
2604  mass.harmonic = m_harmonic;
2605  mass.corporationID = m_corpID;
2606  mass.allianceID = (IsAlliance(m_allyID) ? m_allyID : -1);
2607  into.Append( mass);
2608  DataSector data = DataSector();
2609  data.inertia = m_destiny->GetInertia();
2610  data.maxSpeed = m_destiny->GetMaxVelocity();
2611  data.velX = m_destiny->GetVelocity().x;
2612  data.velY = m_destiny->GetVelocity().y;
2613  data.velZ = m_destiny->GetVelocity().z;
2615  into.Append( data);
2616  switch (mode) {
2617  case Ball::Mode::WARP: {
2618  GPoint target = m_destiny->GetTargetPoint();
2619  WARP_Struct warp;
2620  warp.formationID = 0xFF;
2621  warp.targX = target.x;
2622  warp.targY = target.y;
2623  warp.targZ = target.z;
2624  warp.speed = m_destiny->GetWarpSpeed(); //ship warp speed x10 (dont ask...this is what it is...more dumb ccp shit)
2625  // warp timing. see ShipSE::EncodeDestiny() for notes/updates
2626  warp.effectStamp = -1; //m_destiny->GetStateStamp(); //timestamp when warp started
2627  warp.followRange = 0; //this isnt right
2628  warp.followID = 0; //this isnt right
2629  into.Append(warp);
2630  } break;
2631  case Ball::Mode::FOLLOW: {
2632  FOLLOW_Struct follow;
2633  follow.followID = m_destiny->GetTargetID();
2635  follow.formationID = 0xFF;
2636  into.Append(follow);
2637  } break;
2638  case Ball::Mode::ORBIT: {
2639  ORBIT_Struct orbit;
2640  orbit.targetID = m_destiny->GetTargetID();
2642  orbit.formationID = 0xFF;
2643  into.Append(orbit);
2644  } break;
2645  case Ball::Mode::GOTO: {
2646  GPoint target = m_destiny->GetTargetPoint();
2647  GOTO_Struct go;
2648  go.formationID = 0xFF;
2649  go.x = target.x;
2650  go.y = target.y;
2651  go.z = target.z;
2652  into.Append(go);
2653  } break;
2654  default: {
2655  STOP_Struct main;
2656  main.formationID = 0xFF;
2657  into.Append(main);
2658  } break;
2659  }
2660 
2661  std::string modeStr = "Goto";
2662  switch (mode) {
2663  case 1: modeStr = "Follow"; break;
2664  case 2: modeStr = "Stop"; break;
2665  case 3: modeStr = "Warp"; break;
2666  case 4: modeStr = "Orbit"; break;
2667  case 5: modeStr = "Missile"; break;
2668  case 6: modeStr = "Mushroom"; break;
2669  case 7: modeStr = "Boid"; break;
2670  case 8: modeStr = "Troll"; break;
2671  case 9: modeStr = "Miniball"; break;
2672  case 10: modeStr = "Field"; break;
2673  case 11: modeStr = "Rigid"; break;
2674  case 12: modeStr = "Formation"; break;
2675  }
2676 
2677  _log(SE__DESTINY, "ShipSE::EncodeDestiny(): %s - id:%li, mode:%s, flags:0x%X, Vel:%.1f, %.1f, %.1f", \
2678  GetName(), head.entityID, modeStr.c_str(), head.flags, data.velX, data.velY, data.velZ);
2679 }
2680 
2681 void ShipSE::MakeDamageState(DoDestinyDamageState &into) {
2683  into.recharge = m_self->GetAttribute(AttrShieldRechargeRate).get_float() + 7;
2684  into.timestamp = GetFileTimeNow();
2686  into.structure = 1.0 - (m_self->GetAttribute(AttrDamage).get_float() / m_self->GetAttribute(AttrHP).get_float());
2687 }
2688 
2690  _log(SE__SLIMITEM, "MakeSlimItem for Ship %s(%u)", m_self->name(), m_self->itemID());
2691  PyDict *slim = new PyDict();
2692  slim->SetItemString("itemID", new PyLong(m_self->itemID()));
2693  slim->SetItemString("typeID", new PyInt(m_self->typeID()));
2694  slim->SetItemString("name", new PyString(m_self->itemName()));
2695  slim->SetItemString("ownerID", new PyInt(m_ownerID));
2696  slim->SetItemString("charID", new PyInt(m_self->GetPilot() ? m_self->GetPilot()->GetCharacterID() : 0));
2697  slim->SetItemString("corpID", IsCorp(m_corpID) ? new PyInt(m_corpID) : PyStatic.NewNone());
2698  slim->SetItemString("allianceID", IsAlliance(m_allyID) ? new PyInt(m_allyID) : PyStatic.NewNone());
2699  slim->SetItemString("warFactionID", IsFaction(m_warID) ? new PyInt(m_warID) : PyStatic.NewNone());
2700  slim->SetItemString("bounty", new PyFloat(m_self->GetPilot() ? m_self->GetPilot()->GetBounty() : 0));
2701  slim->SetItemString("securityStatus", new PyFloat(m_self->GetPilot() ? m_self->GetPilot()->GetSecurityRating() : 0.0));
2702  if (m_self->typeID() == itemTypeCapsule) {
2703  slim->SetItemString("launcherID", new PyInt(m_podShipID));
2704  return slim;
2705  } else {
2706  slim->SetItemString("categoryID", new PyInt(m_self->categoryID()));
2707  slim->SetItemString("groupID", new PyInt(m_self->groupID()));
2708  }
2709 
2710  //encode the hiSlot and Subsystem modules list ONLY
2711  std::vector<InventoryItemRef> items;
2713  //m_self->GetMyInventory()->GetItemsByFlagRange(flagSubSystem0, flagSubSystem7, items);
2714  if (!items.empty()) {
2715  PyList *list = new PyList();
2716  for (auto cur : items)
2717  list->AddItem(new_tuple(cur->itemID(), cur->typeID()));
2718 
2719  slim->SetItemString("modules", list );
2720  }
2721 
2722  if (is_log_enabled(DESTINY__DEBUG)) {
2723  _log( DESTINY__DEBUG, "ShipSE::MakeSlimItem() - %s(%u)", GetName(), GetID());
2724  slim->Dump(DESTINY__DEBUG, " ");
2725  }
2726 
2727  return slim;
2728 }
2729 
2731 {
2732  m_oldArmor = 0;
2733  m_oldShield = 0;
2734  m_oldScanRes = 0;
2735  m_oldInertia = 0.0f;
2736  m_oldTargetRange = 0;
2737 
2738  m_boost = BoostData();
2739  m_boosted = false;
2740 }
2741 
2743 {
2744  _log( FLEET__TRACE, "ShipSE::RemoveBoost() - %s(%u)", GetName(), GetID());
2745 
2751 
2753 
2754  ClearBoostData();
2755 }
2756 
2758 {
2759  // note: mining boost applied in mining module code
2760 
2761  // remove existing boost
2762  if (m_boosted)
2763  RemoveBoost();
2764 
2765  _log( FLEET__TRACE, "ShipSE::ApplyBoost() - %s(%u)", GetName(), GetID());
2766 
2767  m_boost = bData;
2773 
2774  uint16 armorHP = m_oldArmor * (1.0f + (0.02f * m_boost.armored)); // 2% increase/level
2775  uint16 shieldHP = m_oldShield * (1.0f + (0.02f * m_boost.siege));// 2% increase/level
2776  uint16 scanRes = m_oldScanRes * (1.0f + (0.02f * m_boost.leader));// 2% increase/level
2777  uint32 targRange = m_oldTargetRange * (1.0f + (0.02f * m_boost.info));// 2% increase/level
2778  float inertia = m_oldInertia * (1.0f - (0.02f * m_boost.skirmish));// 2% decrease/level
2779 
2780  m_shipRef->SetAttribute(AttrInetia, inertia); // lower inertia = lower agility = faster ship
2781  m_shipRef->SetAttribute(AttrArmorHP, armorHP);
2782  m_shipRef->SetAttribute(AttrScanResolution, scanRes); // higher scanRes = faster targeting
2785 
2787 
2788  m_boosted = true;
2789 }
2790 //{'FullPath': u'UI/Messages', 'messageID': 257802, 'label': u'DronesDroppedBecauseOfBandwidthModificationBody'}(u'The drone control bandwidth of your ship has been modified causing you to lose the ability to control some drones.', None, None)
2791 
2793  Character* pChar = GetPilot()->GetChar().get();
2794  sLog.Magenta("ShipSE::LaunchDrone()","%s: Launching drone %u", pChar->name(), dRef->itemID());
2795 
2796  dRef->Move(GetLocationID(), flagNone, true);
2797  dRef->ChangeSingleton(true);
2798 
2799  GPoint position(GetPosition());
2800  position.MakeRandomPointOnSphere(500.0);
2801  dRef->SetPosition(position);
2802 
2803  //now we create an SE to represent it.
2804  FactionData data = FactionData();
2805  data.allianceID = pChar->allianceID();
2806  data.corporationID = pChar->corporationID();
2807  data.factionID = pChar->warFactionID();
2808  data.ownerID = pChar->itemID();
2809  DroneSE* pDrone = new DroneSE(dRef, m_services, m_system, data);
2810 
2811  // tell new drone it's being launched.
2812  pDrone->Launch(this);
2813  // add drone to launched drone map (whether onlined or not)
2814  m_drones.emplace(dRef->itemID(), dRef.get());
2815 
2816  /*
2817  AttrDroneBandwidth = 1271, <-- ship attribute (total)
2818  AttrDroneBandwidthUsed = 1272, <-- drone attribute
2819  AttrDroneBandwidthLoad = 1273, <-- ship attribute (current used)
2820  */
2821  // if ship doesnt have bandwidth for drone, it will not online after launch (inert)
2823  load += dRef->GetAttribute(AttrDroneBandwidthUsed);
2824  if (load <= m_shipRef->GetAttribute(AttrDroneBandwidth)) {
2825  pDrone->Online();
2826  pDrone->GetAI()->SetIdle();
2827  m_shipRef->SetAttribute(AttrDroneBandwidthLoad, load, false); // client dont care
2828  return true;
2829  }
2830  //{'FullPath': u'UI/Messages', 'messageID': 258031, 'label': u'MaxBandwidthExceededBody'}(u"You don't have enough bandwidth to launch {droneName}. You need {bandwidthNeeded} Mbit/s but {droneName} requires {droneBandwidthUsed} Mbit/s.", None, {u'{droneName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'droneName'}, u'{droneBandwidthUsed}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'droneBandwidthUsed'}, u'{bandwidthNeeded}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'bandwidthNeeded'}})
2831  //{'FullPath': u'UI/Messages', 'messageID': 258041, 'label': u'MaxBandwidthExceeded2Body'}(u"You don't have enough bandwidth to launch {droneName}. You need {droneBandwidthUsed} Mbit/s but only have {bandwidthLeft} Mbit/s available.", None, {u'{droneName}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'droneName'}, u'{bandwidthLeft}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'bandwidthLeft'}, u'{droneBandwidthUsed}': {'conditionalValues': [], 'variableType': 10, 'propertyName': None, 'args': 0, 'kwargs': {}, 'variableName': 'droneBandwidthUsed'}})
2832  return false;
2833 }
2834 
2836  m_drones.erase(pSE->GetID());
2837  pSE->GetDroneSE()->Offline();
2839  load -= pSE->GetSelf()->GetAttribute(AttrDroneBandwidthUsed);
2840  m_shipRef->SetAttribute(AttrDroneBandwidthLoad, load, false); // client dont care
2841 }
2842 
2843 void ShipSE::UpdateDrones(std::map<int16, int8> &attribs) {
2844  // update drones in space with new attrib settings
2845  for (auto cur : m_drones) {
2846  cur.second->SetAttribute(AttrDroneFocusFire, attribs[AttrDroneFocusFire]);
2847  cur.second->SetAttribute(AttrDroneIsAgressive, attribs[AttrDroneIsAgressive]);
2848  cur.second->SetAttribute(AttrFightersAttackAndFollow, attribs[AttrFightersAttackAndFollow]);
2849  //cur.second->SetAttribute(AttrDroneIsChaotic, attribs[AttrDroneIsChaotic]); // no longer used?
2850  }
2851 }
2852 
2854  SystemEntity* pSE(nullptr);
2856  for (auto cur : m_drones) {
2857  pSE = m_system->GetSE(cur.first);
2858  if (pSE != nullptr)
2859  if (pSE->IsDroneSE()) {
2860  pSE->GetDroneSE()->Abandon();
2861  load -= pSE->GetSelf()->GetAttribute(AttrDroneBandwidthUsed);
2862  }
2863  }
2864  m_shipRef->SetAttribute(AttrDroneBandwidthLoad, load, false); // client dont care
2865 }
2866 //AttrDroneControlDistance
bool IsLogin()
Definition: Client.h:235
void ProcessHeat()
Definition: Ship.cpp:1130
void Append(const T &value)
Appends a single value to buffer.
Definition: Buffer.h:437
Base Python wire object.
Definition: PyRep.h:66
float GetRemainingCapacity(EVEItemFlags flag) const
Definition: Inventory.h:72
bool isHighPower()
Definition: GenericModule.h:92
#define sConfig
A macro for easier access to the singleton.
bool IsSessionChange()
Definition: Client.h:241
void UpdateMass()
Definition: Ship.cpp:389
unsigned __int8 uint8
Definition: eve-compat.h:46
uint32 m_podShipID
Definition: Ship.h:385
virtual void Process()
bool ContentsLoaded() const
Definition: Inventory.h:62
virtual DroneSE * GetDroneSE()
Definition: SystemEntity.h:135
SystemEntity * GetSE(uint32 entityID) const
bool ValidateItemSpecifics(InventoryItemRef iRef)
Definition: Ship.cpp:2316
void CheckSlotFitLimited(EVEItemFlags flag)
static ShipItemRef Spawn(ItemData &data)
Definition: Ship.cpp:51
~ShipItem() noexcept
Definition: Ship.cpp:40
double GetFollowDistance()
void Online(ShipSE *pShipSE=nullptr)
Definition: Drone.cpp:153
void HeatDamageCheck(GenericModule *pMod)
Definition: Ship.cpp:1272
void SaveShipState()
void SendErrorMsg(const char *fmt,...)
Definition: Client.cpp:2719
void DamageModule(uint32 modID, float amt=1)
Definition: Ship.h:166
#define _log(type, fmt,...)
Definition: logsys.h:124
bool IsDamaged()
Definition: GenericModule.h:85
InventoryItemRef GetLoadedChargeOnModule(EVEItemFlags flag)
Python string.
Definition: PyRep.h:430
DestinyManager * m_destiny
Definition: SystemEntity.h:265
void ScoopDrone(SystemEntity *pSE)
Definition: Ship.cpp:2835
double GetRadius()
Definition: SystemEntity.h:208
void InitAttribs()
Definition: Ship.cpp:191
int32 GetInt(uint32 index) const
Definition: dbcore.cpp:635
void ProcessModules()
Definition: Ship.cpp:343
void GetModuleItemVec(std::vector< InventoryItemRef > &iRefVec)
Definition: Ship.cpp:568
float GetSecurityRating() const
Definition: Client.h:172
void ClearAllTargets(bool notify=true)
bool isMediumPower()
Definition: GenericModule.h:93
Python's dictionary.
Definition: PyRep.h:719
void ClearTarget(SystemEntity *tSE)
void Online(uint32 modID)
Definition: Ship.cpp:999
virtual void AddItem(InventoryItemRef iRef)
Definition: Ship.cpp:468
uint32 m_ownerID
Definition: SystemEntity.h:283
bool IsCharCreation()
Definition: Client.h:433
bool HasAttribute(const uint16 attrID) const
bool SetFlag(EVEItemFlags flag, bool notify=false)
BoostData m_boost
Definition: Ship.h:390
virtual void RemoveItem(InventoryItemRef iRef)
bool get_bool()
Definition: EvilNumber.cpp:157
virtual void AddItem(InventoryItemRef iRef)
ModuleManager * GetModuleManager()
Definition: Ship.h:80
static bool FitModuleSkillCheck(InventoryItemRef item, CharacterRef ch)
Definition: Skill.cpp:230
void UnfitModule(uint32 itemID)
uint8 GetLoadedLinkedCount(GenericModule *pMod)
Definition: Ship.cpp:1676
void VerifyHoldType(EVEItemFlags flag, InventoryItemRef iRef, Client *pClient=nullptr)
Definition: Ship.cpp:1972
void PayInsurance()
Definition: Ship.cpp:2502
void CargoFull()
Definition: Ship.cpp:1335
EVEItemFlags
Definition: EVE_Flags.h:13
virtual void Process()
Definition: Ship.cpp:2440
double MakeRandomFloat(double low, double high)
Generates random real from interval [low; high].
Definition: misc.cpp:114
double y()
Definition: SystemEntity.h:214
void OfflineAll()
Definition: Ship.cpp:1055
void QueueDestinyEvent(PyTuple **multiEvent)
Definition: Client.cpp:2124
UserError & AddTypeName(const char *name, uint32 typeID)
Shorthand method for adding a type's name.
#define sProfiler
Definition: dbcore.cpp:39
void Init()
Definition: Ship.cpp:150
void UnloadModule(uint32 itemID)
virtual bool HasPilot()
Definition: Ship.h:71
virtual bool IsLogin()
Definition: Ship.cpp:2536
uint32 UnlinkWeapon(uint32 moduleID)
Definition: Ship.cpp:1522
Python floating point number.
Definition: PyRep.h:292
const GVector & GetVelocity() const
int32 GetCharacterID() const
Definition: Client.h:113
void DeleteContents()
Definition: Inventory.cpp:273
std::vector< uint32 > m_onlineModuleVec
Definition: Ship.h:280
bool IsInvul()
Definition: Client.h:234
PyDict * GetShipState()
Definition: Ship.cpp:2199
void Jump()
Definition: Ship.cpp:405
int32 GetCorporationID() const
Definition: Client.h:123
void LoadWeaponGroups()
Definition: Ship.cpp:1745
int8 leader
Definition: FleetData.h:71
DroneAIMgr * GetAI()
Definition: Drone.h:75
virtual bool _Load()
PyServiceMgr & m_services
Definition: SystemEntity.h:267
Timer m_processTimer
Definition: Ship.h:383
bool HasEffect(uint16 effectID) const
Definition: ItemType.cpp:208
bool ValidateBoardShip(CharacterRef who)
Definition: Ship.cpp:2267
void CheckGroupFitLimited(EVEItemFlags flag, InventoryItemRef iRef)
void RemoveItem(InventoryItemRef iRef)
Definition: Inventory.cpp:243
UserError & AddFormatValue(const char *name, PyRep *value)
Fluent version of the protected AddKeyword, allows for adding a keyword to the exception.
void SetPosition(const GPoint &pos)
void DamageRandModule()
Definition: Ship.h:167
bool m_isDocking
Definition: Ship.h:287
int8 siege
Definition: FleetData.h:74
void RepairModules()
Definition: Ship.h:144
#define IsMidSlot(flag)
Definition: EVE_Defines.h:361
this is a class that kinda mimics how python polymorph's numbers.
Definition: EvilNumber.h:59
PyPackedRow * GetItemStatusRow() const
void LoadLinkedWeapons(GenericModule *pMod, std::vector< int32 > &chargeIDs)
Definition: Ship.cpp:684
const char * name()
bool IsInSpace()
Definition: Client.h:228
InventoryItemRef srcRef
Definition: EffectsData.h:78
#define IsLowSlot(flag)
Definition: EVE_Defines.h:364
void SendNotifyMsg(const char *fmt,...)
Definition: Client.cpp:2776
CharacterRef GetChar() const
Definition: Client.h:164
Python tuple.
Definition: PyRep.h:567
void GetLoadedCharges(std::map< EVEItemFlags, InventoryItemRef > &charges)
GaFloat x
Definition: GaTypes.h:207
void UpdateDrones(std::map< int16, int8 > &attribs)
Definition: Ship.cpp:2843
Advanced version of UserError that allows to send a full custom message.
Definition: PyExceptions.h:453
int32 m_harmonic
Definition: SystemEntity.h:276
void Dump(FILE *into, const char *pfx) const
Dumps object to file.
Definition: PyRep.cpp:84
uint32 itemID()
Definition: GenericModule.h:97
itemID[count] Create count or of the specified item(from Insider)" ) COMMAND( goto
void Offline()
Definition: Drone.cpp:163
static const uint16 SHIP_PROCESS_TICK_MS
Definition: EVE_Consts.h:25
signed __int8 int8
Definition: eve-compat.h:45
uint32 GetTargetID()
int32 GetAllianceID() const
Definition: Client.h:125
const GPoint & GetPosition() const
Definition: SystemEntity.h:211
void UninstallRig(uint32 itemID)
void Move(uint32 new_location=locTemp, EVEItemFlags flag=flagNone, bool notify=false)
void GetModulesInBank(EVEItemFlags flag, std::vector< GenericModule * > &modVec)
void SaveWeaponGroups()
Definition: Ship.cpp:1733
#define IsHiSlot(flag)
Definition: EVE_Defines.h:358
EvilNumber EvilZero
Definition: EvilNumber.cpp:32
static void SaveWeaponGroups(uint32 shipID, std::multimap< uint32, uint32 > &data)
Definition: ShipDB.cpp:103
void AddItem(PyRep *i)
Definition: PyRep.h:701
void SafeDelete(T *&p)
Deletes and nullifies a pointer.
Definition: SafeMem.h:83
uint16 groupID() const
signed __int32 int32
Definition: eve-compat.h:49
void GetWeapons(std::list< GenericModule * > &weaponList)
bool GetRow(DBResultRow &into)
Definition: dbcore.cpp:552
ModuleManager * m_ModuleManager
Definition: Ship.h:276
TargetManager * m_targMgr
Definition: SystemEntity.h:264
void Warp()
Definition: Ship.cpp:2564
const ItemType & type() const
std::string GetShipDNA()
Definition: Ship.cpp:1902
float GetSpeedFraction()
void Unload()
Definition: Inventory.cpp:62
void InitPod()
Definition: Ship.cpp:171
#define is_log_enabled(type)
Definition: logsys.h:78
void LogOut()
Definition: Ship.cpp:84
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
void SetIdle()
Definition: DroneAI.cpp:142
std::map< GenericModule *, std::list< GenericModule * > > m_linkedWeapons
Definition: Ship.h:281
bool IsLoading()
Definition: GenericModule.h:87
void GetModuleListOfRefsAsc(std::vector< InventoryItemRef > &modVec)
double GetPackagedVolume()
Definition: gpoint.h:33
virtual void Delete()
Definition: Ship.cpp:332
void Heal()
Definition: Ship.cpp:458
InventoryItemRef m_self
Definition: SystemEntity.h:269
PyRep * GetLinkedWeapons()
Definition: Ship.cpp:1691
double GetTimeUSeconds()
Definition: utils_time.cpp:116
Generic class for buffers.
Definition: Buffer.h:40
GenericModule * GetModule(EVEItemFlags flag)
static ShipItemRef Load(uint32 shipID)
Definition: Ship.cpp:46
void ResetEffects()
Definition: Ship.cpp:1872
float m_oldInertia
Definition: Ship.h:396
void SetShipHull(float fraction)
Definition: Ship.cpp:931
InventoryItemRef GetSelf()
Definition: SystemEntity.h:202
ShipItem(uint32 shipID, const ItemType &type, const ItemData &data)
Definition: Ship.cpp:23
int32 GetWarpSpeed()
void LinkAllWeapons()
Definition: Ship.cpp:1416
double GetTimeMSeconds()
Definition: utils_time.cpp:104
Python object.
Definition: PyRep.h:826
void UpdateModules(std::vector< uint32 > modVec)
Client * m_pilot
Definition: Ship.h:273
uint32 m_corpID
Definition: SystemEntity.h:281
bool VerifySlotExchange(EVEItemFlags slot1, EVEItemFlags slot2)
void Warp()
Definition: Ship.cpp:401
PyDict * GetShipInfo()
Definition: Ship.cpp:2153
uint32 GetLocationID()
Definition: SystemEntity.h:209
PyTuple * new_tuple(int64 arg1)
Definition: PyRep.cpp:1160
void ProcessEffects(bool add=false, bool update=false)
Definition: Ship.cpp:1794
PyTuple * MakeDamageState()
float GetBounty() const
Definition: Client.h:171
bool InstallRig(ModuleItemRef mRef, EVEItemFlags flag)
ModuleItemRef GetSelf()
Definition: GenericModule.h:42
Inventory * pInventory
#define codelog(type, fmt,...)
Definition: logsys.h:128
void SetItem(size_t index, PyRep *object)
Stores Python object.
Definition: PyRep.h:610
void OfflineGroup(GenericModule *pMod)
Definition: Ship.cpp:1711
void ClearBoostData()
Definition: Ship.cpp:2730
uint32 m_oldTargetRange
Definition: Ship.h:395
bool IsDocked()
Definition: Client.h:229
static void LoadWeaponGroups(uint32 shipID, DBQueryResult &res)
Definition: ShipDB.cpp:98
void PeelAndLink(uint32 masterID, uint32 slaveID)
Definition: Ship.cpp:1411
uint32 get_uint32()
Definition: EvilNumber.cpp:173
void ReplaceCharges(EVEItemFlags flag, InventoryItemRef newCharge)
Definition: Ship.cpp:1074
float CalculateRechargeRate(float Capacity, float RechargeTimeMS, float Current)
Definition: Ship.cpp:2416
void SetShipCapacitorLevel(float fraction)
Definition: Ship.cpp:881
float DissipateHeat(uint16 attrID, float heat)
Definition: Ship.cpp:1214
float mass() const
Definition: ItemType.h:69
#define sFxDataMgr
bool isLowPower()
Definition: GenericModule.h:91
#define IsValidTarget(itemID)
Definition: EVE_Defines.h:327
static void DeleteInsuranceByShipID(uint32 shipID)
Definition: ShipDB.cpp:65
bool InstallSubSystem(ModuleItemRef mRef, EVEItemFlags flag)
static void TranserFunds(uint32 fromID, uint32 toID, double amount, std::string reason="", uint8 entryTypeID=Journal::EntryType::Undefined, uint32 referenceID=0, uint16 fromKey=Account::KeyType::Cash, uint16 toKey=Account::KeyType::Cash, Client *pClient=nullptr)
uint32 locationID() const
Python integer.
Definition: PyRep.h:231
double GetMaxVelocity()
void OnlineAll()
Definition: Ship.cpp:1050
virtual Client * GetPilot()
Definition: Ship.h:331
void LoadChargesToBank(EVEItemFlags flag, std::vector< int32 > &chargeIDs)
Definition: Ship.cpp:661
SystemManager * m_system
Definition: SystemEntity.h:263
void DeactivateAllModules()
double GetInertia()
double z()
Definition: SystemEntity.h:215
int8 info
Definition: FleetData.h:72
void Activate(int32 itemID, uint16 effectID, int32 targetID, int32 repeat)
void RepairShip(float fraction)
Definition: Ship.cpp:950
void SetAttribute(uint16 attrID, int num, bool notify=true)
uint32 GetID()
Definition: SystemEntity.h:207
uint16 m_oldArmor
Definition: Ship.h:392
bool Check(bool reset=true)
Definition: timer.cpp:62
#define PyStatic
Definition: PyRep.h:1209
void EmptyCargo()
Definition: Ship.cpp:1327
X * get() const
Definition: RefPtr.h:213
#define IsFittingSlot(flag)
Definition: EVE_Defines.h:355
void Activate(int32 itemID, std::string effectName, int32 targetID, int32 repeat)
Definition: Ship.cpp:1039
const char * GetName() const
Definition: Client.h:94
float GetShipInsurancePayout(uint32 shipID)
Definition: ShipDB.cpp:70
const char * GetName() const
Definition: SystemEntity.h:210
const std::string & name() const
Definition: ItemType.h:74
void GetLinkedWeaponMods(EVEItemFlags flag, std::vector< GenericModule * > &modules)
Definition: Ship.cpp:1342
bool Populate(Rsp_CommonGetInfo_Entry &into)
void ProcessEffects(ShipItem *pShip)
Definition: Character.cpp:498
void Jump(bool showCloak=true)
double x()
Definition: SystemEntity.h:213
int32 warFactionID() const
Definition: Character.h:303
float GenerateHeat(uint16 attrID)
Definition: Ship.cpp:1164
uint8 action
Definition: EffectsData.h:73
Python object "ccp_exceptions.UserError".
Definition: PyExceptions.h:121
void LinkWeaponLoop(std::list< GenericModule * > &moduleVec)
Definition: Ship.cpp:1448
Definition: Client.h:66
#define IsSubSystem(flag)
Definition: EVE_Defines.h:370
Definition: Drone.h:46
virtual bool _Load()
Definition: Ship.cpp:63
void AddModuleToOnlineVec(uint32 modID)
Definition: Ship.cpp:562
bool ChangeSingleton(bool singleton, bool notify=false)
static RefPtr StaticCast(const RefPtr< Y > &oth)
Acts as static_cast from one RefPtr to another.
Definition: RefPtr.h:238
unsigned __int32 uint32
Definition: eve-compat.h:50
void UpdateModules()
Definition: Ship.cpp:862
uint32 corporationID() const
Definition: Character.h:300
int8 armored
Definition: FleetData.h:70
void RemoveTarget(SystemEntity *pSE)
EVEItemFlags flag() const
InventoryItemRef GetModuleRef(EVEItemFlags flag)
Definition: Ship.cpp:582
void UnlinkAllWeapons()
Definition: Ship.cpp:1651
std::map< uint32, InventoryItem * > m_drones
Definition: Ship.h:402
void Dock()
Definition: Ship.cpp:361
void ApplyBoost(BoostData &bData)
Definition: Ship.cpp:2757
int8 skirmish
Definition: FleetData.h:75
void UnloadCharge(GenericModule *pMod)
uint32 corporationID
#define IsCorp(itemID)
Definition: EVE_Defines.h:234
void TryModuleLimitChecks(EVEItemFlags flag, InventoryItemRef iRef)
Definition: Ship.cpp:736
bool m_loaded
Definition: Ship.h:227
void GetInventoryMap(std::map< uint32, InventoryItemRef > &invMap)
Definition: Inventory.cpp:453
#define sFxProc
ShipItemRef m_shipRef
Definition: Ship.h:376
void Eject()
Definition: Ship.cpp:350
void Launch(ShipSE *pShipSE)
Definition: Drone.cpp:142
void RemoveTarget(SystemEntity *pSE)
Definition: Ship.cpp:2571
RefPtr< InventoryItem > InventoryItemRef
Definition: ItemRef.h:52
GaFloat y
Definition: GaTypes.h:207
bool HasSkillTrainedToLevel(uint16 skillTypeID, uint8 skillLevel) const
Definition: Character.cpp:584
void CharacterLeavingShip()
double GetFileTimeNow()
Definition: utils_time.cpp:84
bool LaunchDrone(InventoryItemRef dRef)
Definition: Ship.cpp:2792
void RemoveBoost()
Definition: Ship.cpp:2742
void ProcessShipEffects(bool update=false)
Definition: Ship.cpp:1834
RefPtr< ShipItem > ShipItemRef
Definition: ItemRef.h:54
GPoint GetTargetPoint()
uint16 GetAvailableSlotInBank(EVEEffectID slotBank)
#define IsModuleSlot(flag)
Definition: EVE_Defines.h:350
uint16 m_oldScanRes
Definition: Ship.h:394
EVEItemFlags flag()
GenericModule * GetModule(EVEItemFlags flag)
Definition: Ship.h:173
virtual void EncodeDestiny(Buffer &into)
Definition: Ship.cpp:2579
ShipSE(InventoryItemRef self, PyServiceMgr &services, SystemManager *pSystem, const FactionData &data)
Definition: Ship.cpp:2390
const std::string & itemName() const
#define IsCargoHoldFlag(flag)
Definition: EVE_Defines.h:336
int main(int argc, char *argv[])
void ResetShipSystemMgr(SystemManager *pSystem)
Definition: Ship.cpp:2512
void SetShipArmor(float fraction)
Definition: Ship.cpp:913
void PrepForUndock()
Definition: Ship.cpp:1895
virtual Client * GetPilot()
Definition: Ship.h:72
void SendDamageStateChanged()
void Offline(uint32 itemID)
static uint32 CreateItemID(ItemData &data)
void Undock()
Definition: Ship.cpp:370
EvilNumber GetAttribute(const uint16 attrID) const
void LoadCharge(InventoryItemRef chargeRef, EVEItemFlags flag)
virtual void SetPlayer(Client *pClient)
Definition: Ship.cpp:106
virtual void SetPlayer(Client *pClient)
typeID Spawn an NPC with the specified type text Search for items matching the specified query() type()() itemID() copy() materialLevel()() itemID(attributeID)-Retrieves attribute value." ) COMMAND( setattr
bool LoadContents()
Definition: Inventory.cpp:113
virtual void RemoveItem(InventoryItemRef iRef)
Definition: Ship.cpp:532
#define IsFaction(itemID)
Definition: EVE_Defines.h:250
void DamageGroup(GenericModule *pMod)
Definition: Ship.cpp:1246
void ResetModifiers()
Definition: Character.cpp:485
ShipDB m_db
Definition: Ship.h:381
virtual void SetPilot(Client *pClient)
Definition: Ship.cpp:2517
void RepairModule(uint32 itemID, EvilNumber amount)
bool AddModule(ModuleItemRef mRef, EVEItemFlags flag)
bool m_boosted
Definition: Ship.h:391
void DamageRandModule(float chance)
Definition: Ship.cpp:2494
#define IsRigSlot(flag)
Definition: EVE_Defines.h:367
void Online(uint32 itemID)
#define IsHangarFlag(flag)
Definition: EVE_Defines.h:344
PyDict * GetChargeState()
Definition: Ship.cpp:2224
static uint32 CreateItemID(ItemData &data)
Definition: Ship.cpp:59
void RemoveCharge(EVEItemFlags fromFlag)
Definition: Ship.cpp:718
void ClearModuleModifiers()
Definition: Ship.cpp:1858
void traceStack(void)
Definition: misc.cpp:169
uint32 AddItemByFlag(EVEItemFlags flag, InventoryItemRef iRef, Client *pClient=nullptr)
Definition: Ship.cpp:486
virtual void Delete()
EVEItemFlags FindAvailableModuleSlot(InventoryItemRef iRef)
Definition: Ship.cpp:797
void GetActiveModulesHeat(uint8 rack, float &heat)
#define sItemFactory
Definition: ItemFactory.h:165
void StripFitting()
Definition: Ship.cpp:1311
std::string m_towerPass
Definition: Ship.h:399
EvilNumber EvilOne
Definition: EvilNumber.cpp:34
void Dock()
Definition: Ship.cpp:2543
#define IsAlliance(itemID)
Definition: EVE_Defines.h:244
void SaveShip()
Definition: Ship.cpp:1060
float get_float()
Definition: EvilNumber.cpp:184
int32 allianceID() const
Definition: Character.h:302
float GetRemainingVolumeByFlag(EVEItemFlags flag) const
Definition: Ship.cpp:338
void Offline(uint32 modID)
Definition: Ship.cpp:1034
void SetLinkMaster(bool set=false)
AttributeMap * pAttributeMap
void GetModuleRefVec(std::vector< InventoryItemRef > &iRefVec)
Definition: Ship.cpp:577
void MakeRandomPointOnSphere(double radius)
Definition: gpoint.h:46
void SetShipShield(float fraction)
Definition: Ship.cpp:897
void GetItemStatusRow(PyPackedRow *into) const
void MergeModuleGroups(uint32 masterID, uint32 slaveID)
Definition: Ship.cpp:1406
bool IsSlotOccupied(EVEItemFlags flag)
virtual void Abandon()
Definition: Drone.cpp:185
Inventory * GetMyInventory()
Definition: InventoryItem.h:91
unsigned __int16 uint16
Definition: eve-compat.h:48
void SetLinked(bool set=false)
entityID heal the character with the entityID note giving you detailed ship status information gives a list of all dynamic entities and players and their destinyState in this bubble shows some current destiny variables save all items
virtual PyDict * MakeSlimItem()
Definition: Ship.cpp:2689
virtual bool IsDroneSE()
Definition: SystemEntity.h:187
void SetItem(PyRep *key, PyRep *value)
SetItem adds or sets a database entry.
Definition: PyRep.cpp:713
uint32 GetItemsByFlagRange(EVEItemFlags low_flag, EVEItemFlags high_flag, std::vector< InventoryItemRef > &items) const
Definition: Inventory.cpp:502
PyList * ShipGetModuleList()
Definition: Ship.cpp:2247
bool m_isActive
Definition: Ship.h:285
void LoadCharge(InventoryItemRef cRef, EVEItemFlags flag)
Definition: Ship.cpp:601
uint16 typeID() const
InventoryItemRef m_targetRef
Definition: Ship.h:278
bool m_isUndocking
Definition: Ship.h:288
uint8 categoryID() const
virtual bool HasPilot()
void AbandonDrones()
Definition: Ship.cpp:2853
const uint32 m_processTimerTick
Definition: Ship.h:378
virtual bool IsInvul()
Definition: Ship.cpp:2529
Python list.
Definition: PyRep.h:639
GaFloat z
Definition: GaTypes.h:207
static void ClearWeaponGroups(uint32 shipID)
Definition: ShipDB.cpp:92
void MoveModuleSlot(EVEItemFlags slot1, EVEItemFlags slot2)
Definition: Ship.cpp:818
uint32 typeID()
Definition: GenericModule.h:98
uint32 itemID() const
Definition: InventoryItem.h:98
uint16 m_oldShield
Definition: Ship.h:393
virtual Client * GetPilot()
bool GetSingleItemByFlag(EVEItemFlags flag, InventoryItemRef &iRef) const
Definition: Inventory.cpp:489
void UnlinkGroup(uint32 memberID, bool update=false)
Definition: Ship.cpp:1602
void Jump(bool showCloak=true)
Definition: Ship.cpp:2553
int32 quantity() const
Definition: InventoryItem.h:97
Python long integer.
Definition: PyRep.h:261
void LinkWeapon(uint32 masterID, uint32 slaveID)
Definition: Ship.cpp:1365
#define sDataMgr
void RemoveRig(InventoryItemRef iRef)
Definition: Ship.cpp:1067
void Start(uint32 setTimerTime=0, bool changeResetTimer=true)
Definition: timer.cpp:81
uint8 GetLinkedCount(GenericModule *pMod)
Definition: Ship.cpp:1668
static const float BUBBLE_RADIUS_METERS
Definition: BubbleManager.h:32