EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
TargetManager.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 */
33 #include "eve-server.h"
34 
35 #include "EVEServerConfig.h"
36 #include "Profiler.h"
37 #include "Client.h"
39 #include "npc/NPC.h"
40 #include "npc/NPCAI.h"
41 #include "pos/Structure.h"
42 #include "pos/Tower.h"
43 #include "pos/sovStructures/TCU.h"
44 #include "pos/sovStructures/IHub.h"
45 #include "ship/Ship.h"
49 #include "system/TargetManager.h"
50 #include "system/SystemEntity.h"
51 #include "system/SystemBubble.h"
52 
54 : mySE(self)
55 {
56  m_canAttack = false;
57 
58  m_modules.clear();
59  m_targets.clear();
60  m_targetedBy.clear();
61 }
62 
64  double profileStartTime = GetTimeUSeconds();
65 
66  if (m_targets.empty())
67  return false;
68 
69  //process outgoing targeting (outgoing will call incoming as needed)
70  std::map<SystemEntity*, TargetEntry*>::iterator itr = m_targets.begin();
71  while (itr != m_targets.end()) {
72  if ((itr->first == nullptr) or (itr->second == nullptr)) {
73  itr = m_targets.erase(itr);
74  continue;
75  }
76  switch (itr->second->state) {
78  case TargMgr::State::Locked:{ //do nothing
79  } break;
80  case TargMgr::State::Passive: // this will be used with stealth modules (which, ofc, are not written yet)
82  if (itr->second->timer.Check(false)) {
83  itr->second->timer.Disable();
84  itr->second->state = TargMgr::State::Locked;
85  _log(TARGET__TRACE, "%s(%u) has finished locking %s(%u)", \
86  mySE->GetName(), mySE->GetID(), itr->first->GetName(), itr->first->GetID());
87  TargetAdded(itr->first);
88  itr->first->TargetMgr()->TargetedByLocked(mySE);
89  m_canAttack = true;
90  }
91  } break;
92  }
93  ++itr;
94  }
95 
96  if (sConfig.debug.UseProfiling)
97  sProfiler.AddTime(Profile::targets, GetTimeUSeconds() - profileStartTime);
98 
99  return true;
100 }
101 
103  for (auto cur : m_targets)
104  SafeDelete(cur.second);
105  m_targets.clear();
106  for (auto cur : m_targetedBy)
107  SafeDelete(cur.second);
108  m_targetedBy.clear();
109 }
110 
112 { // NOTE this is for players and CAN throw (client calls this inside try/catch block)
113  if (!mySE->HasPilot()) {
114  codelog(TARGET__ERROR, "StartTargeting() called by pilot-less ship %s(%u) to target %s(%u)", \
115  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
116  return false;
117  }
118 
119  //first make sure they are not already in the list
120  if (m_targets.find(tSE) != m_targets.end()) {
121  _log(TARGET__DEBUG, " %s(%u): Told to target %s(%u), but we are already targeting them. Ignoring request.", \
122  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
123  return false;
124  }
125  // get lower of ship and char target skills, with minimum of 1
126  uint8 maxLockedTargets = 1;
127  uint8 maxCharTargets = mySE->GetPilot()->GetChar()->GetSkillLevel(EvESkill::Targeting);
128  maxCharTargets += mySE->GetPilot()->GetChar()->GetSkillLevel(EvESkill::Multitasking);
129  if (maxCharTargets > 0)
130  if (maxLockedTargets < maxCharTargets)
131  maxLockedTargets = maxCharTargets;
132 
133  uint8 maxShipTargets = (uint8)sRef->GetAttribute(AttrMaxLockedTargets).get_uint32();
134  if (maxShipTargets > 0)
135  if (maxLockedTargets > maxShipTargets)
136  maxLockedTargets = maxShipTargets;
137 
138  if (m_targets.size() >= maxLockedTargets) {
139  mySE->GetPilot()->SendNotifyMsg("Your ship and skills combination can only handle %u targets at a time.", maxLockedTargets);
140  _log(TARGET__DEBUG, " %s(%u): Told to target %s(%u), but we already have max targets of %u. Ignoring request.", \
141  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID(), maxLockedTargets);
142  return false;
143  }
144 
145  // Check if target is an invulnerable structure
146  if (tSE->IsTCUSE()) {
148  mySE->GetPilot()->SendNotifyMsg("You cannot target an invulnerable structure.");
149  return false;
150  }
151  } else if (tSE->IsTowerSE()) {
153  mySE->GetPilot()->SendNotifyMsg("You cannot target an invulnerable structure.");
154  return false;
155  }
156  } else if (tSE->IsIHubSE()) {
158  mySE->GetPilot()->SendNotifyMsg("You cannot target an invulnerable structure.");
159  return false;
160  }
161  } else if (tSE->IsOutpostSE()) {
162  if (tSE->GetOutpostSE()->GetState() == EVEPOS::StructureState::Online) { //TODO: This structure state likely will be different for outposts, will change later.
163  mySE->GetPilot()->SendNotifyMsg("You cannot target an invulnerable structure.");
164  return false;
165  }
166  }
167 
168  // Check against max target range
169  double maxTargetRange = sRef->GetAttribute(AttrMaxTargetRange).get_double();
170  GVector rangeToTarget( mySE->GetPosition(), tSE->GetPosition() );
171  // adjust for target radius, in case of ice or other large objects..
172  double targetDistance = rangeToTarget.length();
173  if (tSE->IsAsteroidSE())
174  targetDistance -= tSE->GetRadius();
175  if (targetDistance > maxTargetRange) {
176  mySE->GetPilot()->SendNotifyMsg("Your ship and skills combination can only target to %.0f meters. %s is %.0f meters away.", \
177  maxTargetRange, tSE->GetName(), targetDistance);
178  _log(TARGET__DEBUG, " %s(%u): Told to target %s(%u), but they are too far away. Ignoring request.", \
179  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
180  return false;
181  }
182 
183  // Calculate Time to Lock target:
184  float lockTime = TimeToLock( sRef, tSE );
185 
186  TargetEntry *te = new TargetEntry();
188  te->timer.Start(lockTime *1000); //timer has ms resolution
189  m_targets[tSE] = te;
190  tSE->TargetMgr()->TargetedAdd(mySE);
191 
192  _log(TARGET__INFO, "Pilot %s in %s(%u) started targeting %s(%u) (%.2fs lock time)", \
193  mySE->GetPilot()->GetName(), mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID(), lockTime);
194 
195  sEntityList.AddTargMgr(mySE, this);
196 
197  Dump();
198 
199  return true;
200 }
201 
202 bool TargetManager::StartTargeting(SystemEntity *tSE, float lockTime, uint8 maxLockedTargets, double maxTargetLockRange, bool &chase)
203 { // NOTE this is for npcs
204  //first make sure they are not already in the list
205  if (m_targets.find(tSE) != m_targets.end()) {
206  _log(TARGET__DEBUG, " %s(%u): Told to target %s(%u), but we are already targeting them. Ignoring request.", \
207  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
208  return true;
209  }
210  // Check against max locked target count
211  if (m_targets.size() >= maxLockedTargets){
212  _log(TARGET__DEBUG, " %s(%u): Told to target %s(%u), but we already have max targets. Ignoring request.", \
213  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
214  return false;
215  }
216  // Check against max target range
217  if (mySE->GetPosition().distance(tSE->GetPosition()) > maxTargetLockRange){
218  _log(TARGET__TRACE, " %s(%u): Told to target %s(%u), but they are too far away. Begin Approaching.", \
219  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
220  chase = true;
221  return false;
222  }
223 
224  TargetEntry *te = new TargetEntry();
226  te->timer.Start(lockTime);
227  m_targets[tSE] = te;
228  tSE->TargetMgr()->TargetedAdd(mySE);
229 
230  _log(TARGET__INFO, "NPC %s(%u) started targeting %s(%u) (%.2fs lock time)", \
231  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID(), (lockTime /1000));
232 
233  sEntityList.AddTargMgr(mySE, this);
234 
235  Dump();
236 
237  return true;
238 }
239 
241  std::map<SystemEntity*, TargetEntry*>::iterator itr = m_targets.find(tSE);
242  if (itr != m_targets.end()) {
243  SafeDelete(itr->second);
244  m_targets.erase(itr);
245  }
246  if (m_targets.empty()) {
247  m_canAttack = false;
248  // no targets to process. remove from proc map
249  sEntityList.DeleteTargMgr(mySE);
250  }
251  _log(TARGET__TRACE, "RemoveTarget: %s(%u) has removed target %s(%u).", \
252  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
253 }
254 
256  //let the other entity know they are no longer targeted.
257  tSE->TargetMgr()->TargetedByLost(mySE);
258  //clear it from our own state
259  TargetLost(tSE);
260  if (m_targets.empty()) {
261  m_canAttack = false;
262  // no targets to process. remove from proc map
263  sEntityList.DeleteTargMgr(mySE);
264  }
265  _log(TARGET__TRACE, "ClearTarget: %s(%u) has cleared target %s(%u).", \
266  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
267 }
268 
270  auto cur = m_modules.begin ();
271  auto end = m_modules.end ();
272 
273  ActiveModule* module (nullptr);
274 
275  while (cur != end) {
276  module = cur->second;
277 
278  cur = m_modules.erase (cur);
279 
280  module->AbortCycle ();
281  }
282 }
283 
284 void TargetManager::ClearAllTargets(bool notify/*true*/) {
285  ClearTargets(notify);
287  if (notify)
288  TargetsCleared();
289  _log(TARGET__TRACE, "ClearAllTargets: %s(%u) has cleared all targeting information.", mySE->GetName(), mySE->GetID());
290 }
291 
292 void TargetManager::ClearTargets(bool notify/*true*/) {
293  m_canAttack = false;
294 
295  for (auto cur : m_targets) {
296  // failsafe still chance this code is incomplete
297  if (cur.first->TargetMgr() != nullptr)
298  cur.first->TargetMgr()->TargetedByLost(mySE);
299  SafeDelete(cur.second);
300  _log(TARGET__TRACE, "ClearTargets() - %s(%u) has cleared target %s(%u).",
301  mySE->GetName(), mySE->GetID(), cur.first->GetName(), cur.first->GetID());
302  }
303 
304  m_targets.clear();
305 
306  // no targets to process. remove from proc map
307  sEntityList.DeleteTargMgr(mySE);
308 }
309 
311  if (m_targetedBy.empty())
312  return;
313 
314  std::vector<SystemEntity *> ToNotify;
315  for (auto cur : m_targetedBy) {
316  SafeDelete(cur.second);
317  //do not notify until we clear our target list! otherwise Bad Things happen. (invalidate iterator here)
318  ToNotify.push_back(cur.first);
319  _log(TARGET__TRACE, "ClearFrom() - %s(%u) has added %s(%u) to delete list.", \
320  mySE->GetName(), mySE->GetID(), cur.first->GetName(), cur.first->GetID());
321  }
322 
323  m_targetedBy.clear();
324 
325  for (auto cur : ToNotify)
326  if (cur->TargetMgr() != nullptr)
327  cur->TargetMgr()->TargetLost(mySE);
328 }
329 
331  std::map<SystemEntity *, TargetEntry *>::iterator itr = m_targets.find(tSE);
332  if (itr == m_targets.end())
333  return;
334 
335  SafeDelete(itr->second);
336  m_targets.erase(itr);
337 
338  if (m_targets.empty()) {
339  m_canAttack = false;
340  // no targets to process. remove from proc map
341  sEntityList.DeleteTargMgr(mySE);
342  }
343  _log(TARGET__INFO, "%s(%u) has lost lock on %s(%u)", mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
344 
345  if (mySE->IsSentrySE())
346  return;
347 
348  mySE->DestinyMgr()->EntityRemoved(tSE);
349  if (mySE->IsNPCSE())
350  mySE->GetNPCSE()->TargetLost(tSE);
351  if (!mySE->HasPilot())
352  return;
353  Notify_OnTarget te;
354  te.mode = "lost";
355  te.targetID = tSE->GetID();
356  //te.reason = "Docking";
357  Notify_OnMultiEvent multi;
358  multi.events = new PyList();
359  multi.events->AddItem(te.Encode());
360  PyTuple* tmp = multi.Encode(); //this is consumed below
361  mySE->GetPilot()->SendNotification("OnMultiEvent", "clientID", &tmp);
362 }
363 
365  _log(TARGET__TRACE, "%s(%u) has been locked by %s(%u)", \
366  mySE->GetName(), mySE->GetID(), pSE->GetName(), pSE->GetID());
367  // i think this is redundant....check
368  //mySE->TargetMgr()->TargetedAdd(pSE);
369 }
370 
372  std::map<SystemEntity *, TargetedByEntry *>::iterator itr = m_targetedBy.find(pSE);
373  if (itr == m_targetedBy.end()) {
374  _log(TARGET__DEBUG, "%s(%u) TargetByLost() - Tried to notify %s(%u) of target lost, but they did not have us targeted.", \
375  mySE->GetName(), mySE->GetID(), pSE->GetName(), pSE->GetID());
376  return;
377  }
378 
379  _log(TARGET__TRACE, "%s(%u) is no longer locked by %s(%u)", \
380  mySE->GetName(), mySE->GetID(), pSE->GetName(), pSE->GetID());
381 
382  SafeDelete(itr->second);
383  m_targetedBy.erase(itr);
384  TargetedLost(pSE);
385 }
386 
387 /*
388  OnTarget.mode
389  add - targeting successful
390  clear - clear all targets
391  lost - target lost
392  - Docking
393  - Destroyed
394  otheradd - somebody else has targeted you
395  otherlost - somebody else has stopped targeting you
396  - WarpingOut
397  - StoppedTargeting
398 */
399 
401  _log(TARGET__TRACE, "%s(%u) - adding target %s(%u).", \
402  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
403  if (!mySE->HasPilot())
404  return;
405  PyTuple* up(nullptr);
406  Notify_OnTarget te;
407  te.mode = "add";
408  te.targetID = tSE->GetID();
409  up = te.Encode();
411  OnDamageStateChange odsc;
412  odsc.entityID = tSE->GetID();
413  odsc.state = tSE->MakeDamageState();
414  up = odsc.Encode();
416 }
417 
419  //first make sure they are not already in the list
420  if (m_targetedBy.find(tSE) != m_targetedBy.end()) {
421  _log(TARGET__INFO, "Cannot add %s(%u) to %s(%u)'s locked list: they're already in there.", \
422  tSE->GetName(), tSE->GetID(), mySE->GetName(), mySE->GetID());
423  return;
424  } else {
425  //new entry.
426  _log(TARGET__TRACE, "%s(%u) - %s(%u) has started target lock on me.", \
427  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
428  TargetedByEntry *te = new TargetedByEntry();
429  te->state = TargMgr::State::Locking;
430  m_targetedBy[tSE] = te;
431  }
432  if (mySE->IsNPCSE())
433  mySE->GetNPCSE()->TargetedAdd(tSE);
434  if (!mySE->HasPilot())
435  return;
436  Notify_OnTarget te;
437  te.mode = "otheradd";
438  te.targetID = tSE->GetID();
439  Notify_OnMultiEvent multi;
440  multi.events = new PyList();
441  multi.events->AddItem(te.Encode());
442  PyTuple* tmp = multi.Encode();
443  mySE->GetPilot()->SendNotification("OnMultiEvent", "clientID", &tmp);
444 }
445 
447  _log(TARGET__TRACE, "%s(%u) - %s(%u) has lost target lock on me.", \
448  mySE->GetName(), mySE->GetID(), tSE->GetName(), tSE->GetID());
449  if (!mySE->HasPilot())
450  return;
451  Notify_OnTarget te;
452  te.mode = "otherlost";
453  te.targetID = tSE->GetID();
454  // te.reason = "WarpingOut";
455  // te.reason = "StoppedTargeting";
456  Notify_OnMultiEvent multi;
457  multi.events = new PyList();
458  multi.events->AddItem(te.Encode());
459  PyTuple* tmp = multi.Encode();
460  mySE->GetPilot()->SendNotification("OnMultiEvent", "clientID", &tmp);
461 }
462 
464  _log(TARGET__TRACE, "%s(%u) - i am clearing all target data.", mySE->GetName(), mySE->GetID());
465  if (!mySE->HasPilot())
466  return;
467  Notify_OnTarget te;
468  te.mode = "clear";
469  te.targetID = 0;
470  Notify_OnMultiEvent multi;
471  multi.events = new PyList();
472  multi.events->AddItem(te.Encode());
473  PyTuple* tmp = multi.Encode();
474  mySE->GetPilot()->SendNotification("OnMultiEvent", "clientID", &tmp);
475 }
476 
478 {
479  return (m_targetedBy.find(pSE) != m_targetedBy.end());
480 }
481 
482 SystemEntity* TargetManager::GetFirstTarget(bool need_locked/*false*/) {
483  if (m_targets.empty())
484  return nullptr;
485 
486  if (!need_locked)
487  return m_targets.begin()->first;
488 
489  std::map<SystemEntity *, TargetEntry *>::iterator itr = m_targets.begin();
490  for (; itr != m_targets.end(); ++itr)
491  if (itr->second->state == TargMgr::State::Locked)
492  return itr->first;
493 
494  return nullptr;
495 }
496 
498  PyList* result = new PyList();
499  if (m_targets.empty())
500  return result;
501 
502  std::map<SystemEntity *, TargetEntry *>::const_iterator itr = m_targets.begin();
503  for (; itr != m_targets.end(); ++itr)
504  result->AddItemInt( itr->first->GetID() );
505 
506  return result;
507 }
508 
510  PyList* result = new PyList();
511  if (m_targetedBy.empty())
512  return result;
513 
514  std::map<SystemEntity*, TargetedByEntry*>::const_iterator itr = m_targetedBy.begin();
515  for(; itr != m_targetedBy.end(); ++itr)
516  result->AddItemInt( itr->first->GetID() );
517 
518  return result;
519 }
520 
521 // no longer used. 1Feb18
522 // will be used by advanced NPCs....eventually
523 SystemEntity* TargetManager::GetTarget(uint32 targetID, bool need_locked/*true*/) const {
524  if (m_targets.empty())
525  return nullptr;
526 
527  std::map<SystemEntity*, TargetEntry*>::const_iterator itr = m_targets.begin();
528  for (; itr != m_targets.end(); ++itr) {
529  if (itr->first->GetID() != targetID)
530  continue;
531  //found it...
532  if (need_locked and (itr->second->state != TargMgr::State::Locked)) {
533  _log(TARGET__INFO, "Found target %u, but it is not locked.", targetID);
534  continue;
535  }
536  _log(TARGET__INFO, "Found target %u: %s (nl? %s)", targetID, itr->first->GetName(), need_locked?"yes":"no");
537  return itr->first;
538  }
539  _log(TARGET__INFO, "Unable to find target %u (nl? %s)", targetID, need_locked?"yes":"no");
540  return nullptr; //not found.
541 }
542 
544 {
545  _log(TARGET__INFO, "Adding %s:%s to %s's activeModule list.", \
546  pMod->GetShipRef()->name(), pMod->GetSelf()->name(), mySE->GetName() );
547  // i think this check is redundant...shouldnt be able to activate non-miner on roid.
548  if (mySE->IsAsteroidSE())
549  if (!pMod->IsMiningLaser())
550  return;
551 
552  m_modules.emplace(pMod->itemID(), pMod);
553 }
554 
556 {
557  _log(TARGET__INFO, "Removing the %s on %s from %s's activeModule list.", \
558  pMod->GetSelf()->name(), pMod->GetShipRef()->name(), mySE->GetName() );
559  m_modules.erase(pMod->itemID());
560 }
561 
563 {
564  _log(TARGET__INFO, "%s(%u) has been destroyed. %u modules, %u targets, and %u targeters in maps.", \
565  mySE->GetName(), mySE->GetID(), m_modules.size(), m_targets.size(), m_targetedBy.size());
566 
567  std::string effect = "TargetDestroyed";
568 
569  ClearAllTargets();
570 
571  // iterate thru the map of modules targeting this object, and call Deactivate on each.
572  auto cur = m_modules.begin ();
573  auto end = m_modules.end ();
574 
575  ActiveModule* module (nullptr);
576 
577  while (cur != end) {
578  // TODO: THIS IS A HACK TO FIX A PROBLEM ON THE TARGET MANAGER
579  // TODO: WHEN A MODULE'S CYCLE IS ABORTED BY THIS FUNCTION, IT ENDS UP CALLING
580  // TODO: ActiveModule::Clear DOWN THE ROAD, WHICH IN TURN REMOVES ITEMS FROM THE m_modules
581  // TODO: MAP WHILE WE'RE ITERATING IT, AND THAT'S A NO-NO UNLESS YOU CAN GET THE NEW
582  // TODO: ITERATOR FROM THE ERASE FUNCTION, THAT'S WHY IT'S HANDLED HERE INSTEAD OF LETTING
583  // TODO: THE ActiveModule::Clear TAKE CARE OF IT
584  module = cur->second;
585 
586  // this should advance the iterator without needing to do any cur++ or anything
587  cur = m_modules.erase (cur);
588  // some modules should immediately cease cycle when target destroyed. miners are NOT in this call
589  switch (module->groupID()) {
603  module->AbortCycle();
604  } break;
606  // set success=false and fall thru
607  module->GetProspectModule()->TargetDestroyed();
608  default: {
609  module->Deactivate(effect);
610  } break;
611  }
612  }
613 
614  Dump();
615 }
616 
617 // specific for asteroids; only called by asteroids
619 {
620  if (!mySE->IsAsteroidSE()) {
621  codelog(MODULE__ERROR, "Depleted() called by Non Astroid %s", mySE->GetName());
622  return;
623  }
624  // remove master module here to avoid placement in map
625  m_modules.erase(pMod->itemID());
626 
627  std::multimap<float, MiningLaser*> mMap;
628  // iterate thru the map of modules and add to map as MiningLasers with their mining volume
629  std::map<uint32, ActiveModule*>::iterator itr = m_modules.begin();
630  while (itr != m_modules.end()) {
631  mMap.emplace(itr->second->GetMiningModule()->GetMiningVolume(), itr->second->GetMiningModule());
632  itr = m_modules.erase(itr); //remove module from map here to avoid segfault on rock delete
633  }
634 
635  // call Depleted() on master module with map of active modules
636  pMod->Depleted(mMap);
637 }
638 
640  if ((tSE->IsAsteroidSE()) or (tSE->IsDeployableSE()) or (tSE->IsWreckSE())
641  or (tSE->IsContainerSE()) or (tSE->IsInanimateSE()))
642  return 2.0f;
643 
644  // fixed lock time -allan 24Dec14 -updated 26May15 -revisited after new effects system implementation 25Mar17
646  uint32 sigRad = 25; // set base as capsule with 25m signature radius
647 
648  if ( tSE->GetSelf().get() != nullptr )
651 
652  //https://wiki.eveonline.com/en/wiki/Targeting_speed
653  //locktime = 40000/(scanres * asinh(sigrad)^2)
654  float time = ( 40000 /(scanRes * std::pow(asinh(sigRad), 2))); // higher scan res means faster lock time.
655 
656  /* distance-based modifier to targeting speed? sure, why the hell not? -allan 27.6.15
657  * +0.1s for each 10k distance
658  * distance = pos - targ.pos
659  * disMod = distance /10k (for 10k increments)
660  * time += disMod * 0.1
661  */
662  double distance = sRef->position().distance( tSE->GetPosition());
663  // check for snipers... >85k distance do NOT need additional 7.5+s to targettime
664  // should we check LRT skill for pilots to modify this? yes....not sure how to modify time using this yet...
665  /*
666  * uint8 sLevel = 1;
667  * if (ship->HasPilot()) {
668  * sLevel += ship->GetPilot()->GetChar()->GetSkillLevel(EvESkill::LongRangeTargeting); // bonus to target range
669  * sLevel += ship->GetPilot()->GetChar()->GetSkillLevel(EvESkill::SignatureAnalysis); // skill at operating target systems
670  * sLevel += ship->GetPilot()->GetChar()->GetSkillLevel(EvESkill::Electronics); // basic ship sensor and computer systems
671 }
672 */
673  //if (mySE->IsNPCSE()) // not all snipers are npc
674  if (distance > 85000)
675  distance -= 75000;
676 
677  float disMod = distance /10000;
678  if (disMod < 1)
679  disMod = 0.0f;
680  time += (disMod * 0.1f);
681 
682  return time;
683 }
684 
685 void TargetManager::QueueEvent( PyTuple** event ) const
686 {
687  for (auto cur : m_targetedBy)
688  if (cur.first->HasPilot()) {
689  PyIncRef(*event);
690  cur.first->GetPilot()->QueueDestinyEvent(event);
691  }
692 }
693 
694 void TargetManager::QueueUpdate( PyTuple** update ) const
695 {
696  for (auto cur : m_targetedBy)
697  if (cur.first->HasPilot()) {
698  PyIncRef(*update);
699  cur.first->GetPilot()->QueueDestinyUpdate(update);
700  }
701 }
702 
703 /* debugging methods */
704 std::string TargetManager::TargetList(uint16 &length, uint16 &count) {
705  std::ostringstream str;
706  if (m_targets.empty()) {
707  str << "Targets: <br>";
708  str << " *NONE*<br>";
709  length += 23;
710  } else {
711  str << "Targets: <br>";
712  length += 11;
713  for (auto cur : m_targets) {
714  str << " " << cur.first->GetName();
715  str << " (" << cur.first->GetID() << ") <br>";
716  length += 35;
717  ++count;
718  }
719  }
720  if (m_targetedBy.empty()) {
721  str << "Targeted by: <br>";
722  str << " *NONE*<br>";
723  length += 28;
724  } else {
725  str << "Targeted by: <br>";
726  length += 15;
727  for (auto cur : m_targetedBy) {
728  str << " " << cur.first->GetName();
729  str << " (" << cur.first->GetID() << ") <br>";
730  length += 35;
731  ++count;
732  }
733  }
734  str << "Active Modules: (ship:module)<br>";
735  length += 30;
736  if (m_modules.empty()) {
737  str << " *NONE*";
738  length += 10;
739  } else {
740  for (auto cur : m_modules) {
741  str << " " << cur.second->GetShipRef()->itemName();
742  str << ":" << cur.second->GetSelf()->itemName() << "<br>";
743  length += 55;
744  ++count;
745  }
746  }
747 
748  return str.str();
749 }
750 
751 void TargetManager::Dump() const {
752  if (!is_log_enabled(TARGET__DUMP))
753  return;
754 
755  _log(TARGET__DUMP, "Target Dump for %s(%u):", mySE->GetName(), mySE->GetID());
756  if (m_targets.empty()) {
757  _log(TARGET__DUMP, " No Targets");
758  } else {
759  for (auto cur : m_targets)
760  cur.second->Dump(cur.first);
761  }
762  if (m_targetedBy.empty()) {
763  _log(TARGET__DUMP, " No Targeters");
764  } else {
765  for (auto cur : m_targetedBy)
766  cur.second->Dump(cur.first);
767  }
768 
769  _log(TARGET__DUMP, " Active Modules: (ship:module(moduleID))");
770  if (m_modules.empty()) {
771  _log(TARGET__DUMP, " *NONE*");
772  } else {
773  for (auto cur : m_modules)
774  _log(TARGET__DUMP, "\t\t %s: %s(%u)", cur.second->GetShipRef()->name(), cur.second->GetSelf()->name(), cur.second->itemID());
775  }
776 }
777 
779  if (timer.Enabled()) {
780  _log(TARGET__DUMP, " Targeting %s(%u): %s - Timer Running with %ums remaining.", \
782  } else {
783  _log(TARGET__DUMP, " Targeting %s(%u): %s", pSE->GetName(), pSE->GetID(), TargetManager::GetStateName(state));
784  }
785 }
786 
788  _log(TARGET__DUMP, " Targeted By %s(%u): %s", pSE->GetName(), pSE->GetID(), TargetManager::GetStateName(state));
789 }
790 
792  switch(state) {
793  case TargMgr::State::Idle: return "Idle";
794  case TargMgr::State::Locking: return "Locking";
795  case TargMgr::State::Passive: return "Passive";
796  case TargMgr::State::Locked: return "Locked";
797  default: return "Invalid";
798  }
799 }
800 
801 const char* TargetManager::GetModeName ( uint8 mode ) {
802 
803  switch(mode) {
804  case TargMgr::Mode::None: return "None";
805  case TargMgr::Mode::Add: return "Add";
806  case TargMgr::Mode::Lost: return "Lost";
807  case TargMgr::Mode::Clear: return "Clear";
808  case TargMgr::Mode::OtherAdd: return "OtherAdd";
809  case TargMgr::Mode::OtherLost: return "OtherLost";
810  case TargMgr::Mode::LockedBy: return "LockedBy";
811  default: return "Invalid";
812  }
813 }
#define sConfig
A macro for easier access to the singleton.
PyList * GetTargets() const
unsigned __int8 uint8
Definition: eve-compat.h:46
void QueueUpdate(PyTuple **up) const
void SendNotification(const PyAddress &dest, EVENotificationStream &noti, bool seq=true)
Definition: Client.cpp:2245
void TargetedAdd(SystemEntity *tSE)
GaExpInl GaFloat length() const
Definition: GaTypes.h:156
#define _log(type, fmt,...)
Definition: logsys.h:124
virtual bool IsNPCSE()
Definition: SystemEntity.h:186
double GetRadius()
Definition: SystemEntity.h:208
virtual Prospector * GetProspectModule()
Definition: GenericModule.h:63
void ClearAllTargets(bool notify=true)
void ClearTarget(SystemEntity *tSE)
bool HasAttribute(const uint16 attrID) const
static const char * GetModeName(uint8 mode)
uint32 groupID()
Definition: GenericModule.h:99
uint8 GetState() const
Definition: Structure.h:170
TargetManager(SystemEntity *self)
virtual void TargetLost(SystemEntity *who)
Definition: NPC.cpp:119
const GPoint & position() const
void Depleted(MiningLaser *pMod)
virtual NPC * GetNPCSE()
Definition: SystemEntity.h:134
virtual bool HasPilot()
Definition: SystemEntity.h:258
void QueueDestinyEvent(PyTuple **multiEvent)
Definition: Client.cpp:2124
#define sProfiler
Definition: dbcore.cpp:39
void Dump(SystemEntity *pSE) const
void Dump() const
virtual Client * GetPilot()
Definition: SystemEntity.h:259
virtual StructureSE * GetOutpostSE()
Definition: SystemEntity.h:119
#define asinh
Definition: eve-compat.h:145
#define sEntityList
Definition: EntityList.h:208
static const char * GetStateName(uint8 state)
const char * name()
void ClearTargets(bool notify=true)
void SendNotifyMsg(const char *fmt,...)
Definition: Client.cpp:2776
TargetManager * TargetMgr()
Definition: SystemEntity.h:197
CharacterRef GetChar() const
Definition: Client.h:164
Python tuple.
Definition: PyRep.h:567
uint32 GetRemainingTime() const
Definition: timer.cpp:114
uint32 itemID()
Definition: GenericModule.h:97
virtual bool IsIHubSE()
Definition: SystemEntity.h:167
const GPoint & GetPosition() const
Definition: SystemEntity.h:211
void SafeDelete(T *&p)
Deletes and nullifies a pointer.
Definition: SafeMem.h:83
void TargetLost(SystemEntity *tSE)
void TargetAdded(SystemEntity *tSE)
virtual bool IsTowerSE()
Definition: SystemEntity.h:168
PyList * GetTargeters() const
#define is_log_enabled(type)
Definition: logsys.h:78
std::map< SystemEntity *, TargetEntry * > m_targets
void TargetedLost(SystemEntity *tSE)
SystemEntity * GetFirstTarget(bool need_locked=false)
DestinyManager * DestinyMgr()
Definition: SystemEntity.h:198
double GetTimeUSeconds()
Definition: utils_time.cpp:116
void RemoveTarget(SystemEntity *tSE)
InventoryItemRef GetSelf()
Definition: SystemEntity.h:202
bool Enabled() const
Definition: timer.h:41
void ClearFromTargets()
PyTuple * MakeDamageState()
ModuleItemRef GetSelf()
Definition: GenericModule.h:42
#define codelog(type, fmt,...)
Definition: logsys.h:128
virtual bool IsContainerSE()
Definition: SystemEntity.h:157
uint32 get_uint32()
Definition: EvilNumber.cpp:173
virtual bool IsMiningLaser() const
Definition: GenericModule.h:73
void RemoveTargetModule(ActiveModule *pMod)
SystemEntity * GetTarget(uint32 targetID, bool need_locked=true) const
uint32 GetID()
Definition: SystemEntity.h:207
X * get() const
Definition: RefPtr.h:213
void EntityRemoved(SystemEntity *pSE)
std::map< SystemEntity *, TargetedByEntry * > m_targetedBy
void AddItemInt(int32 intval)
Definition: PyRep.h:702
virtual void AbortCycle()
const char * GetName() const
Definition: Client.h:94
const char * GetName() const
Definition: SystemEntity.h:210
void QueueDestinyUpdate(PyTuple **update, bool DoPackage=false, bool IsSetState=false)
Definition: Client.cpp:2131
float TimeToLock(ShipItemRef sRef, SystemEntity *tSE) const
ShipItemRef GetShipRef()
Definition: GenericModule.h:43
void Depleted(std::multimap< float, MiningLaser * > &mMap)
SystemEntity * mySE
unsigned __int32 uint32
Definition: eve-compat.h:50
#define PyIncRef(op)
Definition: PyRep.h:56
std::map< uint32, ActiveModule * > m_modules
virtual bool IsAsteroidSE()
Definition: SystemEntity.h:176
virtual bool IsWreckSE()
Definition: SystemEntity.h:188
std::string TargetList(uint16 &length, uint16 &count)
void TargetDestroyed()
Definition: Prospector.h:36
virtual TowerSE * GetTowerSE()
Definition: SystemEntity.h:120
virtual bool IsTCUSE()
Definition: SystemEntity.h:165
virtual void TargetedAdd(SystemEntity *who)
Definition: NPC.cpp:123
virtual bool IsDeployableSE()
Definition: SystemEntity.h:177
void TargetedByLost(SystemEntity *tSE)
EvilNumber GetAttribute(const uint16 attrID) const
double get_double()
Definition: EvilNumber.cpp:191
int8 GetSkillLevel(uint16 skillTypeID, bool zeroForNotInjected=true) const
Definition: Character.cpp:575
void QueueEvent(PyTuple **up) const
virtual bool IsInanimateSE()
Definition: SystemEntity.h:144
Definition: gpoint.h:70
GaExpInl GaFloat distance(const GaVec3 &oth) const
Definition: GaTypes.h:158
void AddTargetModule(ActiveModule *pMod)
virtual void Deactivate(std::string effect="")
virtual TCUSE * GetTCUSE()
Definition: SystemEntity.h:129
virtual bool IsSentrySE()
Definition: SystemEntity.h:162
virtual IHubSE * GetIHubSE()
Definition: SystemEntity.h:131
unsigned __int16 uint16
Definition: eve-compat.h:48
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 kick all and halt server immediate command list all items in current location s gives list of cargo contents and volumes in all holds list current session values show current ship DNA show current objects in their destiny state
void TargetedByLocked(SystemEntity *tSE)
void Dump(SystemEntity *pSE) const
bool IsTargetedBy(SystemEntity *pSE)
Python list.
Definition: PyRep.h:639
bool StartTargeting(SystemEntity *tSE, ShipItemRef sRef)
virtual bool IsOutpostSE()
Definition: SystemEntity.h:175
void Start(uint32 setTimerTime=0, bool changeResetTimer=true)
Definition: timer.cpp:81