EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Damage.cpp
Go to the documentation of this file.
1 /*
2  ------------------------------------------------------------------------------------
3  LICENSE:
4  ------------------------------------------------------------------------------------
5  This file is part of EVEmu: EVE Online Server Emulator
6  Copyright 2006 - 2021 The EVEmu Team
7  For the latest information visit https://evemu.dev
8  ------------------------------------------------------------------------------------
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License along with
19  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20  Place - Suite 330, Boston, MA 02111-1307, USA, or go to
21  http://www.gnu.org/copyleft/lesser.txt.
22  ------------------------------------------------------------------------------------
23  Author: Zhur
24  Rewrite: Allan
25 */
26 
27 
28 #include "system/Damage.h"
29 
30 #include "../../eve-common/EVE_Damage.h"
31 //#include "packets/Damage.h"
32 
33 #include "Client.h"
34 #include "EntityList.h"
35 #include "EVEServerConfig.h"
37 #include "npc/NPC.h"
38 #include "npc/NPCAI.h"
39 #include "npc/Drone.h"
40 #include "ship/Ship.h"
42 #include "system/Container.h"
43 #include "system/SystemBubble.h"
45 
46 /*
47 DAMAGE
48 DAMAGE__ERROR
49 DAMAGE__WARNING
50 DAMAGE__MESSAGE
51 DAMAGE__INFO
52 DAMAGE__TRACE
53 DAMAGE__DEBUG
54 */
55 
56 // this is for turrets
57 Damage::Damage(SystemEntity* pSE, InventoryItemRef wRef, float kin, float ther, float emp, float exp, float mod, uint16 eID)
58 : srcSE(pSE), effectID(eID), weaponRef(wRef), chargeRef(InventoryItemRef(nullptr))
59 {
60  em = emp;
61  kinetic = kin;
62  thermal = ther;
63  explosive = exp;
64  modifier = mod;
65 }
66 
67 // this is for npcs
69 : srcSE(pSE), effectID(eID), weaponRef(wRef), chargeRef(InventoryItemRef(nullptr))
70 {
71  modifier = mod;
72 
77 
78  _log(DAMAGE__WARNING, "Damage:C'tor - Called by source %s(%u) with weapon %s(%u).",
79  srcSE->GetName(), srcSE->GetID(), wRef->name(), wRef->itemID() );
80 }
81 
82 // this is for missiles
84 : srcSE(pSE), effectID(eID), weaponRef(wRef), chargeRef(cRef)
85 {
86  modifier = 1;
87 
92 
93  _log(DAMAGE__WARNING, "Damage:C'tor - Called by source %s(%u) with weapon %s(%u) using charge %s(%u).",
94  srcSE->GetName(), srcSE->GetID(), wRef->name(), wRef->itemID(), cRef->name(), cRef->itemID() );
95 }
96 
97 // No specific damage dealt here, just killed
98 Damage::Damage(SystemEntity* pSE, bool fatal_blow/*false*/)
99 : srcSE(pSE), effectID(EVEEffectID::targetAttack)
100 {
101  assert(fatal_blow and "Damage() fatal_blow called without 2nd param being true!");
102 
103  em = kinetic = thermal = explosive = 0.0f;
104  weaponRef = InventoryItemRef(nullptr);
105  chargeRef = InventoryItemRef(nullptr);
106 }
107 
109  double profileStartTime = GetTimeUSeconds();
110 
111  if (is_log_enabled(DAMAGE__MESSAGE)) {
112  if (d.srcSE->IsNPCSE()) {
113  _log(DAMAGE__MESSAGE, "%s(%u): Initializing %.2f damage from NPC %s(%u) with K:%.3f, T:%.3f, EM:%.3f, E:%.3f",\
114  GetName(), GetID(), d.GetTotal(), d.srcSE->GetName(), d.srcSE->GetID(), \
115  d.GetKinetic(), d.GetThermal(), d.GetEM(), d.GetExplosive() );
116  } else if (d.srcSE->IsDroneSE()){
117  _log(DAMAGE__MESSAGE, "%s(%u): Initializing %.2f damage from Drone %s(%u) with K:%.3f, T:%.3f, EM:%.3f, E:%.3f",\
118  GetName(), GetID(), d.GetTotal(), d.srcSE->GetName(), d.srcSE->GetID(), \
119  d.GetKinetic(), d.GetThermal(), d.GetEM(), d.GetExplosive() );
120  } else if (d.srcSE->HasPilot()) {
121  _log(DAMAGE__MESSAGE, "%s(%u): Initializing %.2f damage from %s's %s(%u) using %s(%u) %s with K:%.3f, T:%.3f, EM:%.3f, E:%.3f",\
122  GetName(), GetID(), d.GetTotal(), d.srcSE->GetPilot()->GetName(), d.srcSE->GetName(), d.srcSE->GetID(), \
123  d.weaponRef->name(), d.weaponRef->itemID(), (d.chargeRef ? d.chargeRef->name() : ""), \
124  d.GetKinetic(), d.GetThermal(), d.GetEM(), d.GetExplosive() );
125  } else {
126  _log(DAMAGE__MESSAGE, "%s(%u): Initializing %.2f damage from unknown source.", GetName(), GetID(), d.GetTotal());
127  }
128  }
129 
130  int8 damageID = 0;
131  switch (d.weaponRef->groupID()) {
133  case EVEDB::invGroups::Missile_Launcher_Bomb: // not sure here
136  case EVEDB::invGroups::Missile_Launcher_Defender: // not sure here
142  // apply damage modifier from config
143  d *= sConfig.rates.missileDamage;
144  // should this be adjusted based on damage?
145  damageID = 6;
146  } break;
148  /* TODO
149  * this damage will need to be adjusted based on distance from target, then called for each target,
150  * and modified/corrected as the weapon implementation is completed.
151  * all modifiers to be calc'd in weapon code and sent here for correct damageID
152  */
153  damageID = 5;
154  } break;
156  // these dont do any damage
157  // update this to use real toHit data (once we implement them....)
158  damageID = MakeRandomInt(0,8);
159  } break;
160  default: {
161  float modifier = d.GetModifier();
162  d *= modifier;
163  if (modifier == 3.0f) { damageID = 8; } //strikes perfectly, wrecking
164  else if (modifier > 1.2501f) { damageID = 7; } //places an excellent hit
165  else if (modifier > 0.9999f) { damageID = 6; } //aims well
166  else if (modifier > 0.7501f) { damageID = 5; } //hits
167  else if (modifier > 0.6251f) { damageID = 4; } //lightly hits
168  else if (modifier > 0.4121f) { damageID = 3; } //barely scratches
169  else if (modifier > 0.3751f) { damageID = 2; } //glances off
170  else if (modifier > 0.2501f) { damageID = 1; } //barely misses
171  else { damageID = 0; } //misses completely
172  _log(DAMAGE__TRACE, "%s(%u): Modifier: %.3f, damageID: %u.", GetName(), GetID(), modifier, damageID);
173  } break;
174  }
175 
176  // apply damage modifier from config
177  d *= sConfig.rates.damageRate;
178 
179  // this is calculated and created on every call...
180  Damage DamageToShield = d.MultiplyDup(
185 
186  bool killed = false;
187  float total_damage(0.0f);
188  float shield_damage(DamageToShield.GetTotal());
189  float available_shield(m_self->GetAttribute(AttrShieldCharge).get_float());
190  if (shield_damage <= available_shield) {
203  total_damage += shield_damage;
204  float new_charge = available_shield - shield_damage;
205  m_self->SetAttribute(AttrShieldCharge, new_charge);
206 
207  _log(DAMAGE__DEBUG, "%s(%u): Applying %.2f damage to shields. New charge: %.2f.",
208  GetName(), GetID(), shield_damage, new_charge);
209  } else {
210  // get fraction of damage partial shield absorbs, and lower total damage by that fraction
211  d *= (1 - (available_shield /shield_damage));
212  total_damage += available_shield;
213 
214  if (available_shield > 0.0f) {
215  _log(DAMAGE__INFO, "%s(%u): Shield depleted with %.2f damage. %.2f damage remains.",
216  GetName(), GetID(), available_shield, d.GetTotal());
218  }
219 
220  //Armor:
222  Damage DamageToArmor = d.MultiplyDup(
227 
228  float armor_damage = DamageToArmor.GetTotal();
229  if (armor_damage <= available_armor) {
230  if (HasPilot()) {
232  float new_damage = d.GetTotal() * 0.01;
233  float hull_damage = m_self->GetAttribute(AttrDamage).get_float() + new_damage;
234  _log(DAMAGE__DEBUG, "%s(%u): Applying %.2f leakthru damage to structure. New structure damage: %.2f",
235  GetName(), GetID(), new_damage, hull_damage);
236  m_self->SetAttribute(AttrDamage, hull_damage);
237  // remove this leakthru damage from armor damage
238  armor_damage -= new_damage;
239  }
240  }
241  total_damage += armor_damage;
242  float new_damage = m_self->GetAttribute(AttrArmorDamage).get_float() + armor_damage;
243  m_self->SetAttribute(AttrArmorDamage, new_damage);
244  _log(DAMAGE__DEBUG, "%s(%u): Applying %.2f damage to armor. New armor damage: %.2f",
245  GetName(), GetID(), armor_damage, new_damage);
246  } else {
247  d *= (1 - (available_armor /armor_damage));
248  total_damage += available_armor;
249 
250  if (available_armor > 0) {
251  _log(DAMAGE__INFO, "%s(%u): Armor depleted with %.2f damage. %.2f damage remains.",
252  GetName(), GetID(), available_armor, d.GetTotal());
254  }
255 
256  //Hull/Structure:
257  //The base hp and damage attributes represent structure.
258  float available_hull = m_self->GetAttribute(AttrHP).get_float() - m_self->GetAttribute(AttrDamage).get_float();
259  Damage DamageToHull = d.MultiplyDup(
264 
265  float hull_damage = DamageToHull.GetTotal();
266  if (hull_damage < available_hull) {
267  total_damage += hull_damage;
268  float new_damage = m_self->GetAttribute(AttrDamage).get_float() + hull_damage;
269  m_self->SetAttribute(AttrDamage, new_damage);
270  _log(DAMAGE__DEBUG, "%s(%u): Applying %.2f damage to structure. New structure damage: %.2f",
271  GetName(), GetID(), hull_damage, new_damage);
272  } else {
273  total_damage += available_hull;
274  //dead....
275  _log(DAMAGE__INFO, "%s(%u): %.2f damage has depleted our structure. Time to explode.",
276  GetName(), GetID(), hull_damage);
277  killed = true;
278  }
279 
280  // module damage.
281  // after armor is gone, make damage to random module.
282  if (HasPilot())
283  GetShipSE()->DamageRandModule(sConfig.server.ModuleDamageChance); // config option for random module damage chance
284  }
285  }
286 
287  if (killed) {
288  if (m_killed)
289  return true;
290 
291  m_killed = true;
292 
293  // OnNotify:OnTransmission - (235799, `You have killed this defenseless NPC, bully. Also, you have killed this NPC and are receiving this message.`)
295 
296  Killed(d); // this must NOT remove dead SE from system.
297  SystemEntity::Killed(d); // this removes dead SE from system then deletes itemRef and all its contents
298  } else {
304  if (HasPilot()) {
305  // notify player of damage received
306  PyDict* dict = new PyDict();
307  dict->SetItemString("source", new PyInt(d.srcSE->GetID()));
308  dict->SetItemString("weapon", new PyInt((d.chargeRef.get() != nullptr ? d.chargeRef->typeID() : d.weaponRef->typeID())));
309  dict->SetItemString("target", new PyInt(GetID()));
310  dict->SetItemString("damage", new PyFloat(total_damage));
311  PyTuple* tuple = new PyTuple(3);
312  tuple->SetItem(0, new PyString("OnDamageMessage"));
313  tuple->SetItem(1, new PyString(Dmg::Msg::Taken[damageID]));
314  tuple->SetItem(2, dict);
315  GetPilot()->QueueDestinyEvent(&tuple);
316  }
317  if (d.srcSE->HasPilot()) {
318  //notify to player of damage done:
319  PyDict* dict = new PyDict();
320  dict->SetItemString("weapon", new PyInt((d.chargeRef.get() != nullptr ? d.chargeRef->typeID() : d.weaponRef->typeID())));
321  dict->SetItemString("target", new PyInt(GetID()));
322  dict->SetItemString("damage", new PyFloat(total_damage));
323  PyTuple* tuple = new PyTuple(3);
324  bool banked = false;
325  tuple->SetItem(0, new PyString("OnDamageMessage"));
326  if (d.weaponRef->IsModuleItem()) {
328  if (pMod != nullptr)
329  if (pMod->IsLinked())
330  banked = true;
331  }
332  if (banked) {
333  tuple->SetItem(1, new PyString(Dmg::Msg::Banked[damageID]));
334  } else {
335  tuple->SetItem(1, new PyString(Dmg::Msg::Given[damageID]));
336  }
337  tuple->SetItem(2, dict);
338  d.srcSE->GetPilot()->QueueDestinyEvent(&tuple);
339  } else if (d.srcSE->IsDroneSE()) {
340  // verify drone has owner set
341  if (d.srcSE->GetDroneSE()->GetOwner() != nullptr) {
342  // notify player of damage done by drone
343  PyDict* dict = new PyDict();
344  dict->SetItemString("source", new PyInt(d.srcSE->GetID()));
345  dict->SetItemString("target", new PyInt(GetID()));
346  /*
347  PyTuple* tuple = new PyTuple(2);
348  tuple->AddItem(0, PyStatic.NewNone()); // i dont know what this is
349  tuple->AddItem(1, new PyInt(d.srcSE->GetDroneSE()->GetOwner()->GetCharID())):
350  */
351  //dict->SetItemString("owner", tuple));
352  dict->SetItemString("damage", new PyFloat(total_damage));
353  PyTuple* tuple = new PyTuple(3);
354  tuple->SetItem(0, new PyString("OnDamageMessage"));
355  tuple->SetItem(1, new PyString(Dmg::Msg::Taken[damageID]));
356  tuple->SetItem(2, dict);
357  d.srcSE->GetDroneSE()->GetOwner()->QueueDestinyEvent(&tuple);
358  } else {
359  // make error about active drone with no owner set
360  _log(DRONE__WARNING, "Drone %u attacking %s with no owner set.", d.srcSE->GetID(), GetName());
361  }
362  }
363 
365  }
366 
367  if (sConfig.debug.UseProfiling)
368  sProfiler.AddTime(Profile::damage, GetTimeUSeconds() - profileStartTime);
369 
370  return killed;
371 }
372 
373 void ShipSE::Killed(Damage &fatal_blow) {
374  if ((m_bubble == nullptr) or (m_destiny == nullptr) or (m_system == nullptr))
375  return; // make error here?
376 
377  m_shipRef->SetPopped(true);
378 
379  /* {'messageKey': 'ShipExploded', 'dataID': 17881627, 'suppressable': True, 'bodyID': 258841, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 258840, 'messageID': 1558}
380  * u'ShipExplodedBody'}(u'Your ship has been destroyed by {[character]charID.name}.', None, {u'{[character]charID.name}': {'conditionalValues': [], 'variableType': 0, 'propertyName': 'name', 'args': 0, 'kwargs': {}, 'variableName': 'charID'}})
381  */
382  uint32 killerID = 0, locationID = GetLocationID();
383  Client* pClient(nullptr);
384  SystemEntity* killer(fatal_blow.srcSE);
385 
386  if (killer->HasPilot()) {
387  pClient = killer->GetPilot();
388  killerID = pClient->GetCharacterID();
389  } else if (killer->IsDroneSE()) {
390  pClient = killer->GetDroneSE()->GetOwner();
391  if (pClient == nullptr) {
393  sLog.Error("Ship::Killed()", "killer == IsDrone and pPlayer == nullptr");
394  EvE::traceStack();
395  } else {
396  killerID = pClient->GetCharacterID();
397  }
398  } else {
399  killerID = killer->GetID();
400  }
401 
402  // AttrFwLpKill
403 
404  // log faction kill in dynamic data -allan
405  MapDB::AddKill(locationID);
406  MapDB::AddFactionKill(locationID);
407 
408  // set up basic wreck data
409  GPoint wreckPosition = m_destiny->GetPosition();
410  if (wreckPosition.isNaN()) {
411  sLog.Error("Ship::Killed()", "Wreck Position is NaN");
412  return;
413  }
414  uint32 wreckTypeID = sDataMgr.GetWreckID(m_self->typeID());
415  if (!IsWreckTypeID(wreckTypeID)) {
416  sLog.Error("Ship::Killed()", "Could not get wreckType for %s of type %u", m_self->name(), m_self->typeID());
417  // default to generic frigate wreck till i get better checks and/or complete wreck data
418  wreckTypeID = 26557;
419  }
420 
421  std::string wreck_name = m_self->itemName() + " Wreck";
422 
423  if (!m_self->HasPilot()) {
424  // Spawn a wreck for the Ship that was destroyed:
425  ItemData wreckItemData(wreckTypeID, killerID, locationID, flagNone, wreck_name.c_str(), wreckPosition, itoa(m_allyID));
426  WreckContainerRef wreckItemRef = sItemFactory.SpawnWreckContainer( wreckItemData );
427  if (wreckItemRef.get() == nullptr) {
428  sLog.Error("Ship::Killed()", "Creating Wreck Item Failed for %s of type %u", wreck_name.c_str(), wreckTypeID);
429  return;
430  }
431 
432  if (is_log_enabled(PHYSICS__TRACE))
433  _log(PHYSICS__TRACE, "Ship::Killed() - Ship %s(%u) Position: %.2f,%.2f,%.2f. Wreck %s(%u) Position: %.2f,%.2f,%.2f.", \
434  GetName(), GetID(), x(), y(), z(), wreckItemRef->name(), wreckItemRef->itemID(), wreckPosition.x, wreckPosition.y, wreckPosition.z);
435 
437  wreckEntity.allianceID = killer->GetAllianceID();
439  wreckEntity.corporationID = killer->GetCorporationID();
440  wreckEntity.factionID = sDataMgr.GetWreckFaction(wreckTypeID);
441  wreckEntity.groupID = EVEDB::invGroups::Wreck;
442  wreckEntity.itemID = wreckItemRef->itemID();
443  wreckEntity.itemName = wreck_name;
444  wreckEntity.ownerID = killerID;
445  wreckEntity.typeID = wreckTypeID;
446  wreckEntity.position = wreckPosition;
447 
448  if (!m_system->BuildDynamicEntity(wreckEntity, m_self->itemID())) {
449  sLog.Error("Ship::Killed()", "Spawning Wreck Failed: typeID or typeName not supported: '%u'", wreckTypeID);
450  ; // PyException( MakeCustomError ( "Spawning Wreck Failed: typeID or typeName not supported." ) );
451  wreckItemRef->Delete();
452  return;
453  }
454 
456  // wreck was created successfully. drop loot and add to wreck.
457  DropLoot(wreckItemRef, m_self->groupID(), killerID);
458 
459  return;
460  }
461 
462  Client* pPilot(m_self->GetPilot());
463  if (pPilot == nullptr)
464  return; // make error here
465 
466  if (pClient != nullptr)
467  if (m_system->GetSystemSecurityRating() > 0) {
468  /* http://www.eveinfo.net/wiki/ind~4067.htm
469  * relative_sec_status_penalty = base_penalty * system_truesec * (1 + (victim_sec_status - agressor_sec_status) / 90)
470  * The actual drop in security status seen by the attacker is a function of their current security status and the relative penalty:
471  * security status loss = relative_penalty * (agressor_sec_status + 10)
472  */
474  double modifier = (1 + ((pPilot->GetSecurityRating() - pClient->GetSecurityRating()) / 90));
475  double penalty = 6.0f * m_system->GetSystemSecurityRating() * modifier;
476  double loss = penalty * ( pClient->GetSecurityRating() + 10);
477  loss *= sConfig.rates.secRate;
478  pClient->GetChar()->secStatusChange( loss );
479  }
480 
481  /* populate kill data for killMail and save to db -allan 01May16 --updated 13July17 */
482  CharKillData data = CharKillData();
483  data.solarSystemID = m_system->GetID();
484  data.victimCharacterID = pPilot->GetCharacterID();
486  data.victimAllianceID = m_allyID;
487  data.victimFactionID = m_warID;
488  data.victimShipTypeID = m_self->typeID();
489 
490  data.finalCharacterID = killerID;
491  data.finalCorporationID = killer->GetCorporationID();
492  data.finalAllianceID = killer->GetAllianceID();
493  data.finalFactionID = (killer->GetWarFactionID() > 500021 ? 500021 : killer->GetWarFactionID());
494  data.finalShipTypeID = killer->GetTypeID();
495  data.finalWeaponTypeID = fatal_blow.weaponRef->typeID();
496  data.finalSecurityStatus = 0; /* fix this */
497  data.finalDamageDone = fatal_blow.GetTotal();
498 
499  uint32 totalHP = m_self->GetAttribute(AttrHP).get_int();
500  totalHP += m_self->GetAttribute(AttrArmorHP).get_int();
502  data.victimDamageTaken = totalHP;
503 
504  std::stringstream blob;
505  std::vector<InventoryItemRef> survivedItems;
506  if (pPilot->InPod()) {
507  blob << "<items><i t=" << data.victimShipTypeID << " f=0 s=1 d=0 x=1/></items>";
508  } else {
509  AbortCycle();
510  AbandonDrones();
511 
512  // remove all charges (per packet data) ...why???
513  //GetShipItemRef()->UnloadAllModules();
514 
515  blob << "<items>";
516  /* killBlob contains destroyed/dropped items. u'<items><i t=3651 f=0 d=0 x=1/><i t=3634 f=0 d=0 x=1/></items>' -allan 13July17
517  " i*" tag is decoded as follows:
518  t = item.typeID
519  f = item.flag
520  s = item.singleton
521  d = item.qtyDropped
522  x = item.qtyDestroyed
523  */
524  std::map<uint32, InventoryItemRef> deadShipInventory;
525  deadShipInventory.clear();
526  GetShipItemRef()->GetMyInventory()->GetInventoryMap(deadShipInventory);
527  if (deadShipInventory.empty()) {
528  blob << "<i t=" << data.victimShipTypeID << " f=0 s=1 d=0 x=1/>";
529  } else {
530  uint32 s = 0, d = 0, x = 0;
531  for (auto cur : deadShipInventory) {
532  d = 0;
533  x = cur.second->quantity();
534  s = (cur.second->isSingleton() ? 1 : 0);
535  if (cur.second->categoryID() == EVEDB::invCategories::Blueprint) {
536  // singleton for bpo = 1, bpc = 2.
537  BlueprintRef bpRef = BlueprintRef::StaticCast(cur.second);
538  s = (bpRef->copy() ? 2 : s);
539  }
540 
541  blob << "<i t=" << cur.second->typeID() << " f=" << cur.second->flag() << " s=" << s ;
542  // all contained items have 50% chance of drop, except rigs, which do not survive
543  // todo: add damage to item, if applicable, from ship explosion
544  //cur.second->SetAttribute(AttrDamage, 5);
545  if (IsRigSlot(cur.second->flag())) {
546  /* just avoiding survive check */;
547  } else if (IsEven(MakeRandomInt(0, 100))) {
548  // item survived. check qty for drop
549  if (x > 1) {
550  d = MakeRandomInt(0, x);
551  x -= d;
552  }
553  // move item to vector for insertion into wreck later on
554  survivedItems.push_back(cur.second);
555  }
556  blob << " d=" << d << " x=" << x << "/>";
557  }
558  }
559  blob << "</items>";
560  }
561 
562  data.killBlob = blob.str().c_str();
563  data.killTime = GetFileTimeNow();
564  data.moonID = 0;
565 
566  pPilot->GetChar()->LogKill(data);
567 
568  if (pPilot->InPod()) {
569  // log podKill
570  MapDB::AddPodKill(locationID);
571 
572  if (pClient != nullptr)
573  pClient->GetChar()->PayBounty(pPilot->GetChar());
574 
575  std::string corpse_name = pPilot->GetName();
576  corpse_name += "'s Frozen Corpse";
577  uint32 corpseTypeID = 10041; // typeID from 'invTypes' table for "Frozen Corpse"
578  ItemData corpseItemData(corpseTypeID, m_ownerID, locationID, flagNone, corpse_name.c_str(), wreckPosition);
579  InventoryItemRef corpseItemRef = sItemFactory.SpawnItem( corpseItemData );
580  if (corpseItemRef.get() == nullptr) {
581  sLog.Error("Ship::Killed()", "Creating Corpse Item Failed for %s of type %u", corpse_name.c_str(), corpseTypeID);
583  corpseEntity.allianceID = m_allyID;
585  corpseEntity.corporationID = m_corpID;
586  corpseEntity.factionID = m_warID;
587  corpseEntity.groupID = EVEDB::invGroups::Biomass;
588  corpseEntity.itemID = corpseItemRef->itemID();
589  corpseEntity.itemName = corpse_name;
590  corpseEntity.ownerID = 1; //would this be 'owned' by killer?
591  corpseEntity.typeID = corpseTypeID;
592  corpseEntity.position = wreckPosition;
593  if (!m_system->BuildDynamicEntity(corpseEntity)) {
594  sLog.Error("Ship::Killed()", "Spawning Corpse Failed: typeID or typeName not supported: '%u'", corpseTypeID);
595  } else if (is_log_enabled(PHYSICS__TRACE)) {
596  _log(PHYSICS__TRACE, "Ship::Killed() - Pod %s(%u) Position: %.2f,%.2f,%.2f. Corpse %s(%u) Position: %.2f,%.2f,%.2f.", \
597  GetName(), GetID(), x(), y(), z(), corpseItemRef->name(), corpseItemRef->itemID(), wreckPosition.x, wreckPosition.y, wreckPosition.z);
598  }
599  }
600 
601  // this method will reset char variables to last clone state after being podded. NOTE *** NOT TESTED YET ***
602  pPilot->ResetAfterPodded();
603  } else {
604  PayInsurance();
605 
607 
608  uint16 groupID = m_self->groupID();
609  GPoint podPosition(wreckPosition);
610  podPosition.MakeRandomPointOnSphere(GetShipItemRef()->radius() + pPilot->GetPod()->radius() + MakeRandomFloat(100, 200));
611  // this resets client ship data
612  pPilot->ResetAfterPopped(podPosition);
613 
614  ItemData wreckItemData(wreckTypeID, pPilot->GetCharacterID(), locationID, flagNone, wreck_name.c_str(), wreckPosition, itoa(m_allyID));
615  WreckContainerRef wreckItemRef = sItemFactory.SpawnWreckContainer( wreckItemData );
616  if (wreckItemRef.get() == nullptr) {
617  sLog.Error("Ship::Killed()", "Creating Wreck Item Failed for %s of type %u", wreck_name.c_str(), wreckTypeID);
618  return;
619  }
620 
621  if (is_log_enabled(PHYSICS__TRACE))
622  _log(PHYSICS__TRACE, "Ship::Killed() - Ship %s(%u) Position: %.2f,%.2f,%.2f. Wreck %s(%u) Position: %.2f,%.2f,%.2f.", \
623  GetName(), GetID(), x(), y(), z(), wreckItemRef->name(), wreckItemRef->itemID(), wreckPosition.x, wreckPosition.y, wreckPosition.z);
624 
626  wreckEntity.allianceID = killer->GetAllianceID();
628  wreckEntity.corporationID = killer->GetCorporationID();
629  wreckEntity.factionID = sDataMgr.GetWreckFaction(wreckTypeID);
630  wreckEntity.groupID = EVEDB::invGroups::Wreck;
631  wreckEntity.itemID = wreckItemRef->itemID();
632  wreckEntity.itemName = wreck_name;
633  wreckEntity.ownerID = pPilot->GetCharacterID();
634  wreckEntity.typeID = wreckTypeID;
635  wreckEntity.position = wreckPosition;
636 
637  if (!m_system->BuildDynamicEntity(wreckEntity, m_self->itemID())) {
638  sLog.Error("Ship::Killed()", "Spawning Wreck Failed for typeID %u", wreckTypeID);
639  wreckItemRef->Delete();
640  return;
641  }
642 
643  DropLoot(wreckItemRef, groupID, killerID);
644 
645  for (auto cur: survivedItems)
646  cur->Move(wreckItemRef->itemID(), flagNone); // populate wreck with items that survived
647  }
648 }
float modifier
Definition: Damage.h:94
#define sConfig
A macro for easier access to the singleton.
uint32 finalDamageDone
virtual DroneSE * GetDroneSE()
Definition: SystemEntity.h:135
float kinetic
Definition: Damage.h:90
double radius() const
uint32 finalCorporationID
uint32 victimDamageTaken
static const char * Taken[9]
Definition: EVE_Damage.h:38
#define _log(type, fmt,...)
Definition: logsys.h:124
float explosive
Definition: Damage.h:93
Python string.
Definition: PyRep.h:430
#define IsWreckTypeID(typeID)
Definition: EVE_Defines.h:203
DestinyManager * m_destiny
Definition: SystemEntity.h:265
InventoryItemRef chargeRef
Definition: Damage.h:87
virtual bool IsNPCSE()
Definition: SystemEntity.h:186
uint32 finalCharacterID
float GetSecurityRating() const
Definition: Client.h:172
virtual void Killed(Damage &fatal_blow)
Python's dictionary.
Definition: PyRep.h:719
uint32 m_ownerID
Definition: SystemEntity.h:283
void SendJettisonPacket() const
virtual ShipSE * GetShipSE()
Definition: SystemEntity.h:137
void PayInsurance()
Definition: Ship.cpp:2502
ShipItemRef GetShipItemRef()
Definition: Ship.h:362
double MakeRandomFloat(double low, double high)
Generates random real from interval [low; high].
Definition: misc.cpp:114
double y()
Definition: SystemEntity.h:214
virtual bool HasPilot()
Definition: SystemEntity.h:258
void QueueDestinyEvent(PyTuple **multiEvent)
Definition: Client.cpp:2124
GaExpInl bool isNaN() const
Definition: GaTypes.h:194
#define sProfiler
Definition: dbcore.cpp:39
static void AddKill(uint32 sysID)
Definition: MapDB.cpp:250
virtual Client * GetPilot()
Definition: SystemEntity.h:259
Python floating point number.
Definition: PyRep.h:292
SystemBubble * m_bubble
Definition: SystemEntity.h:262
int32 GetCharacterID() const
Definition: Client.h:113
static void AddFactionKill(uint32 sysID)
Definition: MapDB.cpp:256
SystemEntity * srcSE
Definition: Damage.h:84
const float GetSystemSecurityRating()
Definition: SystemManager.h:86
uint32 GetID() const
Definition: SystemManager.h:80
int32 victimFactionID
const char * name()
CharacterRef GetChar() const
Definition: Client.h:164
Python tuple.
Definition: PyRep.h:567
GaFloat x
Definition: GaTypes.h:207
bool BuildDynamicEntity(const DBSystemDynamicEntity &entity, uint32 launcherID=0)
signed __int8 int8
Definition: eve-compat.h:45
EvilNumber EvilZero
Definition: EvilNumber.cpp:32
uint16 groupID() const
Client * GetOwner()
Definition: Drone.h:74
#define is_log_enabled(type)
Definition: logsys.h:78
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
Definition: gpoint.h:33
InventoryItemRef m_self
Definition: SystemEntity.h:269
bool IsEven(int64 number)
Definition: misc.h:88
double GetTimeUSeconds()
Definition: utils_time.cpp:116
void PayBounty(CharacterRef cRef)
Definition: Character.cpp:1281
static const char * Banked[9]
Definition: EVE_Damage.h:64
float em
Definition: Damage.h:92
uint32 m_corpID
Definition: SystemEntity.h:281
float GetKinetic()
Definition: Damage.h:45
uint32 GetLocationID()
Definition: SystemEntity.h:209
int64 get_int()
Definition: EvilNumber.cpp:166
uint32 solarSystemID
void SetItem(size_t index, PyRep *object)
Stores Python object.
Definition: PyRep.h:610
uint16 GetID()
Definition: SystemBubble.h:91
Definition: Damage.h:33
uint32 victimCorporationID
Python integer.
Definition: PyRep.h:231
float GetEM()
Definition: Damage.h:44
SystemManager * m_system
Definition: SystemEntity.h:263
uint16 finalShipTypeID
double z()
Definition: SystemEntity.h:215
int32 GetAllianceID()
Definition: SystemEntity.h:216
void SetAttribute(uint16 attrID, int num, bool notify=true)
uint32 GetID()
Definition: SystemEntity.h:207
EVEEffectID
Definition: EVE_Effects.h:16
X * get() const
Definition: RefPtr.h:213
const char * GetName() const
Definition: Client.h:94
uint32 victimCharacterID
int32 finalFactionID
float GetModifier()
Definition: Damage.h:47
const char * GetName() const
Definition: SystemEntity.h:210
Damage(SystemEntity *pSE, InventoryItemRef wRef, float mod, uint16 eID)
Definition: Damage.cpp:68
double x()
Definition: SystemEntity.h:213
Definition: Client.h:66
double finalSecurityStatus
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
virtual bool isGlobal()
Definition: SystemEntity.h:142
EVEItemFlags flag() const
void GetInventoryMap(std::map< uint32, InventoryItemRef > &invMap)
Definition: Inventory.cpp:453
ShipItemRef m_shipRef
Definition: Ship.h:376
RefPtr< InventoryItem > InventoryItemRef
Definition: ItemRef.h:52
GaFloat y
Definition: GaTypes.h:207
float GetThermal()
Definition: Damage.h:43
double GetFileTimeNow()
Definition: utils_time.cpp:84
static void AddPodKill(uint32 sysID)
Definition: MapDB.cpp:262
GenericModule * GetModule(EVEItemFlags flag)
Definition: Ship.h:173
int64 MakeRandomInt(int64 low, int64 high)
Generates random integer from interval [low; high].
Definition: misc.cpp:109
uint32 GetCorporationID()
Definition: SystemEntity.h:218
const std::string & itemName() const
float GetTotal() const
Definition: Damage.h:48
void SendDamageStateChanged()
void SendTerminalExplosion(uint32 shipID, uint32 bubbleID, bool isGlobal=false) const
void DropLoot(WreckContainerRef wreckRef, uint32 groupID, uint32 owner)
EvilNumber GetAttribute(const uint16 attrID) const
uint16 finalWeaponTypeID
uint16 victimShipTypeID
virtual void Killed(Damage &fatal_blow)
Definition: Damage.cpp:373
static const char * Given[9]
Definition: EVE_Damage.h:26
virtual bool IsModuleItem()
Definition: InventoryItem.h:86
void DamageRandModule(float chance)
Definition: Ship.cpp:2494
#define IsRigSlot(flag)
Definition: EVE_Defines.h:367
void SetPopped(bool set=false)
Definition: Ship.h:90
const GPoint & GetPosition() const
void traceStack(void)
Definition: misc.cpp:169
void secStatusChange(float amount)
Definition: Character.h:294
#define sItemFactory
Definition: ItemFactory.h:165
float get_float()
Definition: EvilNumber.cpp:184
void MakeRandomPointOnSphere(double radius)
Definition: gpoint.h:46
Damage MultiplyDup(float kinetic_multiplier, float thermal_multiplier, float em_multiplier, float explosive_multiplier) const
Definition: Damage.h:50
uint16 GetTypeID()
Definition: SystemEntity.h:203
void AbortCycle()
Definition: Ship.h:356
int32 finalAllianceID
Inventory * GetMyInventory()
Definition: InventoryItem.h:91
bool ApplyDamage(Damage &d)
Definition: Damage.cpp:108
float GetExplosive()
Definition: Damage.h:46
unsigned __int16 uint16
Definition: eve-compat.h:48
InventoryItemRef weaponRef
Definition: Damage.h:86
int32 victimAllianceID
std::string killBlob
virtual bool IsDroneSE()
Definition: SystemEntity.h:187
float thermal
Definition: Damage.h:91
uint16 typeID() const
virtual bool HasPilot()
void AbandonDrones()
Definition: Ship.cpp:2853
GaFloat z
Definition: GaTypes.h:207
const char * itoa(int64 num)
Convers num to string.
uint32 itemID() const
Definition: InventoryItem.h:98
void SetItemString(const char *key, PyRep *value)
SetItemString adds or sets a database entry.
Definition: PyRep.h:812
virtual Client * GetPilot()
int32 GetWarFactionID()
Definition: SystemEntity.h:217
#define sDataMgr