EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
NPCAI.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  AI Version: 0.57
26 */
27 
40 #include "eve-server.h"
41 
42 #include "Client.h"
44 #include "npc/NPC.h"
45 #include "npc/NPCAI.h"
46 #include "ship/Missile.h"
47 #include "system/DestinyManager.h"
48 #include "system/Damage.h"
49 #include "system/SystemBubble.h"
50 
52 : m_state(NPCAI::State::Idle),
53  m_npc(who),
54  m_destiny(who->DestinyMgr()),
55  m_self(who->GetSelf()),
56  m_processTimer(0),
57  m_mainAttackTimer(0),
58  m_missileTimer(0),
59  m_warpOutTimer(0),
60  m_shieldBoosterTimer(0),
61  m_armorRepairTimer(0),
62  m_beginFindTarget(0),
63  m_warpScramblerTimer(0),
64  m_webifierTimer(0)
65 {
66  assert(m_self.get() != nullptr);
67  m_webber = false;
68  m_warpScram = false;
69  m_isWandering = false;
70 
72 
73  /* set npc ship data */
78  if (m_launcherCycleTime > 100) {
80  } else {
81  m_missileTypeID = 0;
82  }
83 
84  // AttrEntityDefenderChance = 497, <<< for defender missiles
85 
88  // ship speeds
89  // absolute (boosted) Max Ship Speed
91  // Orbit Velocity
92  m_orbitSpeed = m_self->GetAttribute(AttrEntityCruiseSpeed).get_uint32(); // ship speed when not chasing target
93  //AttrEntityChaseMaxDelay - time before 'chase speed' kicks in
94  //AttrEntityChaseMaxDelayChance - chance npc will wait AttrEntityChaseMaxDelay before chasing
95  //AttrEntityChaseMaxDuration - max time a chase will last (unless weapons fired)
96  //AttrEntityChaseMaxDurationChance - chance that any chase will last for AttrEntityChaseMaxDuration
97 
98  // ship distances
99  //AttrEntityMaxWanderRange
100  // Optimal Range - TODO: test for 0
101  m_optimalRange = m_self->GetAttribute(AttrMaxRange).get_uint32(); // distance which npc starts using weapons
102  // Accuracy falloff (distance past optimal range at which accuracy has fallen by half) - TODO: test for 0
105  // Orbit Range, Follow Range - npc tries to stay at this distance from active target
106  m_flyRange = m_self->GetAttribute(AttrEntityFlyRange).get_uint32(); //AttrOrbitRange is 0 for npc
107  if (!m_flyRange)
108  m_flyRange = 0;
109  // distance for Speed Boost activation (this needs to be revisited)
111  if (!m_boostRange)
112  m_boostRange = 0;
113  // some npcs have flyRange > boostRange. this corrects it. (extends boost range)
114  if (m_flyRange > m_boostRange)
116  // max firing range default:10000 (lowest in db is 1000)
118  // this should be set according to npc size.
119  if (m_maxAttackRange < 1000)
120  m_maxAttackRange = 10000;
121 
122  // 'sight' range (undefined in db)
123  float radius = m_self->GetAttribute(AttrRadius).get_float();
124  if (radius < 30) {
125  m_sightRange = 2500;
126  } else if (radius < 60) {
127  m_sightRange = 5000;
128  } else if (radius < 150) {
129  m_sightRange = 8000;
130  } else if (radius < 280) {
131  m_sightRange = 12000;
132  } else if (radius < 550) {
133  m_sightRange = 15000;
134  } else {
135  m_sightRange = 20000;
136  }
139 
140  // ship targets
142  if (m_maxAttackTargets < 1)
143  m_maxAttackTargets = 1;
145  if (m_maxLockedTargets < 1) {
146  if (m_maxAttackTargets > 1) {
148  } else {
149  m_maxLockedTargets = 1;
150  }
151  }
152 
155  // this is chance an npc has of delaying it's rep (if applicable)
164  } else {
167  }
170 
171  // this is chance an npc has of delaying it's sebo (if applicable)
180  } else {
183  }
186 
187  // advanced AI variables only used by sleepers for now (and on live). will update advanced npcs to use these also
189  m_useTargSwitching = true;
190  } else {
191  m_useTargSwitching = false;
192  }
194  m_useSecondTarget = true;
195  } else {
196  m_useSecondTarget = false;
197  }
199  m_useSigRadius = true;
201  } else {
202  m_useSigRadius = false;
204  }
207  } else {
208  m_switchTargChance = 0;
209  }
210 
213  } else {
214  m_warpScramRange = 0;
215  }
218  } else {
219  m_warpScramChance = 0;
220  }
221 
222  /*
223  AttrWarpScrambleRange = 103,
224  AttrWarpScrambleStrength = 105,
225  AttrEntityWarpScrambleChance = 504,
226  AttrWarpScrambleDuration = 505,
227  AttrModifyTargetSpeedRange = 514
228  */
229 
230  /*
231  AttrEntityEquipmentMin = 456,
232  AttrEntityEquipmentMax = 457,
233  */
234 
235  /*
236  AttrEntityTargetJam = 928,
237  AttrEntityTargetJamDuration = 929,
238  AttrEntityTargetJamDurationChance = 930, // npcActivationChanceAttributeID in dgmEffects
239  AttrEntityCapacitorDrainDurationChance = 931, // npcActivationChanceAttributeID in dgmEffects
240  AttrEntitySensorDampenDurationChance = 932, // npcActivationChanceAttributeID in dgmEffects
241  AttrEntityTrackingDisruptDurationChance = 933, // npcActivationChanceAttributeID in dgmEffects
242  AttrEntityTargetPaintDurationChance = 935, // npcActivationChanceAttributeID in dgmEffects
243  AttrEntityTargetJamMaxRange = 936,
244  AttrEntityCapacitorDrainMaxRange = 937,
245  AttrEntitySensorDampenMaxRange = 938,
246  AttrEntityTrackingDisruptMaxRange = 940,
247  AttrEntityTargetPaintMaxRange = 941,
248  AttrEntityCapacitorDrainDuration = 942,
249  AttrEntitySensorDampenDuration = 943,
250  AttrEntityTrackingDisruptDuration = 944,
251  AttrEntityTargetPaintDuration = 945,
252  AttrEntityCapacitorDrainAmount = 946,
253  AttrEntitySensorDampenMultiplier = 947,
254  AttrEntityTrackingDisruptMultiplier = 948,
255  AttrEntityTargetPaintMultiplier = 949,
256  AttrEntitySensorDampenFallOff = 950,
257  AttrEntityTrackingDisruptFallOff = 951,
258  AttrEntityCapacitorFallOff = 952,
259  AttrEntityTargetJamFallOff = 953,
260  AttrEntityTargetPaintFallOff = 954,
261  */
262 
263  // does this need to be running if there are no players in bubble?
264  // yes...npcs will warp out when no targets in sight range, but need a process tic to do that.
265  // m_processTimer.Start(m_attackSpeed);
266 
267  // maybe this can be used to tell spawnMgr to respawn this npc as required....
268  // AttrEntityGroupRespawnChance = 640,
269 }
270 
272  if (m_destiny->IsWarping())
273  return;
274 
275  if (m_warpOutTimer.Check(false)) {
276  // disallow warpout if spawn has active respawn timer (spawn is being chained)
277  if (m_npc->GetSpawnMgr()->IsChaining(m_npc->SysBubble()->GetID())) {
280  }
281  }
282 
283  /* NPCAI::State definitions -allan 25July15 (UD 1June16)
284  * Idle, // not doing anything, nothing in sight....idle. call Wander() to loosely orbit random object in bubble ~10-20k at 1/2 orbit speed
285  * Chasing, // target within npc sight range. attacking begins here. use m_maxSpeed to get within falloff
286  * Following, // between optimal and falloff. try to get closer, but still orbiting and attacking
287  * Engaged, // actively fighting (in orbit). use m_orbitSpeed.
288  * Fleeing, // running away....use m_maxSpeed then warp away when out of range (does this make sense??)
289  * Signaling // calling for help..use m_orbitSpeed *2 to speed tank while calling for reinforcements
290  */
291  switch(m_state) {
292  case NPCAI::State::Idle: {
293  if (m_beginFindTarget.Check()) {
294  std::vector<Client*> clientVec;
295  clientVec.clear();
296  DestinyManager* pDestiny(nullptr);
297  m_npc->SysBubble()->GetPlayers(clientVec); // what about player drones? yes...later
298  for (auto cur : clientVec) {
299  if (cur->IsInvul())
300  continue;
301  if (cur->GetShipSE() == nullptr)
302  continue;
303  if (cur->InPod()) {
304  if (sConfig.npc.TargetPod) {
305  if (m_npc->SystemMgr()->GetSystemSecurityRating() > sConfig.npc.TargetPodSec)
306  continue;
307  } else {
308  continue;
309  }
310  }
311  pDestiny = cur->GetShipSE()->DestinyMgr();
312  if (pDestiny == nullptr) // this shouldnt be needed, but whatever...
313  continue;
314  if (pDestiny->IsCloaked() or pDestiny->IsWarping())
315  continue;
316  if (m_npc->GetPosition().distance(cur->GetShipSE()->GetPosition()) > m_sightRange)
317  continue;
318 
319  Target(cur->GetShipSE());
320  return;
321  }
322  if (sConfig.npc.IdleWander)
323  if (!m_isWandering)
324  SetWander();
325  } else {
326  if (!m_beginFindTarget.Enabled())
327  m_beginFindTarget.Start(m_attackSpeed); //find target is based on npc attack speed.
328  }
329  } break;
332  case NPCAI::State::Engaged: {
333  if (m_npc->TargetMgr()->HasNoTargets()) {
334  _log(NPC__AI_TRACE, "%s(%u): Stopped %s - HasNoTargets = true.", m_npc->GetName(), m_npc->GetID(), GetStateName(m_state).c_str());
335  SetIdle();
336  return;
337  }
338  SystemEntity* pSE = m_npc->TargetMgr()->GetFirstTarget(false);
339  if (pSE == nullptr) {
340  _log(NPC__AI_TRACE, "%s(%u): Stopped %s - GetFirstTarget() returned NULL.", m_npc->GetName(), m_npc->GetID(), GetStateName(m_state).c_str());
341  SetIdle();
342  return;
343  }
344  if (pSE->SysBubble() == nullptr) {
345  ClearTarget(pSE);
346  return;
347  }
348  CheckDistance(pSE);
349  if (m_missileTimer.Check())
351  } break;
356  _log(NPC__AI_TRACE, "%s(%u): Called %s - needs to be completed.", m_npc->GetName(), m_npc->GetID(), GetStateName(m_state).c_str());
358  // not sure how im gonna do these
359  } break;
360  }
361 
365 
369 
370 }
371 
373  // more to this here....
374  return (m_state != NPCAI::State::Idle);
375 }
376 
378 {
380 
383  return;
384  }
385 
387  SystemManager* pSys = m_npc->SystemMgr();
388 
397  if (pSys->PlayerCount()) {
398  // pSys->GetAnomMgr();
399  uint32 newBeltID = pSys->GetRandBeltID();
400  if (newBeltID == sBubbleMgr.GetBeltID(m_npc->SysBubble()->GetID()))
401  newBeltID = pSys->GetRandBeltID();
402 
403  SystemEntity* newSE = pSys->GetSE(newBeltID);
404  m_destiny->WarpTo(newSE->GetPosition());
405  m_npc->GetSpawnMgr()->MoveSpawn(m_npc, sBubbleMgr.FindBubble(newSE));
406  }
407 }
408 
410 {
411  if (m_npc->GetSpawnMgr() == nullptr)
412  return;
413  if (!m_isWandering) {
414  _log(NPC__AI_TRACE, "%s(%u): Wandering: No Targets within my sight range of %um", \
416  m_isWandering = true;
417  }
418 
419  SystemBubble* pBubble = m_npc->SysBubble();
420 
421  // wandering. nothing to shoot. look for target.
422  if (pBubble->IsAnomaly() or pBubble->IsIncursion() or pBubble->IsMission()) {
423  return;
424  } else if (pBubble->HasDynamics() and pBubble->IsBelt()) {
425  // pick random entity and loosely orbit it. if no entity found, orbit center of belt
426  SystemEntity* pSE = pBubble->GetRandomEntity();
427  if (pSE == nullptr)
428  pSE = m_npc->SystemMgr()->GetSE(sBubbleMgr.GetBeltID(pBubble->GetID()));
429  if (pSE == nullptr) {
430  _log(NPC__ERROR, "%s(%u): Wandering: No Target or beltSE found.", m_npc->GetName(), m_npc->GetID());
431  // nothing here...leave bubble
432  WarpOut();
433  return;
434  }
436  uint16 orbitDistance = MakeRandomInt(10000, 20000);
437  m_destiny->Orbit(pSE, orbitDistance);
438  _log(NPC__AI_TRACE, "%s(%u): Just for shits-n-giggles, I\'m gonna orbit %s(%u) at %um.", \
439  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID(), orbitDistance);
440  } else {
442  m_destiny->Stop();
443  }
444 }
445 
448  return;
449  // not doing anything....idle.
450 
453  _log(NPC__AI_TRACE, "%s(%u): Idle: returning to idle.", \
454  m_npc->GetName(), m_npc->GetID());
456  m_destiny->Stop();
458 
466 
467  SystemBubble* pBubble = m_npc->SysBubble();
468  //disallow warpout if anomaly, incursion or mission rat
469  if (pBubble->IsAnomaly() or pBubble->IsIncursion() or pBubble->IsMission())
470  return;
471 
472  //disallow warpout by NOT setting timer.
473  if (sConfig.npc.WarpOut > 0)
474  if (m_npc->GetSpawnMgr() != nullptr)
475  m_warpOutTimer.Start(sConfig.npc.WarpOut *1000); // s to ms
476 }
477 
479  if (pSE == nullptr)
480  return;
483  return;
484  _log(NPC__AI_TRACE, "%s(%u): Begin chasing. Target is %s(%u).", \
485  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
486  // target out of range to attack/follow, but within npc sight range....use mwd/ab if equiped
488  m_destiny->GotoPoint(pSE->GetPosition()); //head towards target
491 }
492 
494  if (pSE == nullptr)
495  return;
497  return;
498  _log(NPC__AI_TRACE, "%s(%u): Begin following. Target is %s(%u).", \
499  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
500  // too close to chase, but to far to engage
502  m_destiny->Follow(pSE, m_falloff); //try to get inside falloff range
505 }
506 
508  if (pSE == nullptr)
509  return;
511  return;
512  _log(NPC__AI_TRACE, "%s(%u): Begin engaging. Target is %s(%u).", \
513  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
514  // actively fighting
516  m_destiny->Orbit(pSE, m_optimalRange); //try to get inside orbit range
519 }
520 
521 // not used yet
523  if (pSE == nullptr)
524  return;
526  return;
527  _log(NPC__AI_TRACE, "%s(%u): Begin fleeing. Target is %s(%u).", \
528  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
529  // actively fleeing
530  // use superspeed to disengage, then warp. << both these will need to be written.
531  // this state is only usable by higher-class npcs.
535 }
536 
537 // not used yet
539  if (pSE == nullptr)
540  return;
542  return;
543  _log(NPC__AI_TRACE, "%s(%u): Begin signaling. Target is %s(%u).", \
544  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
545  // actively signaling
546  // start speedtanking while signaling. (im sure this is cheating, but fuckem.)
547  // this state is only usable by higher-class npcs.
549  m_destiny->Orbit(pSE, m_falloff); //try to get outside orbit range
552 }
553 
555 {
556  if (pSE == nullptr)
557  return;
558  double dist = m_npc->GetPosition().distance(pSE->GetPosition());
559  if ((dist > m_sightRange) and (!m_npc->TargetMgr()->IsTargetedBy(pSE))) {
560  _log(NPC__AI_TRACE, "%s(%u): CheckDistance: %s(%u) is too far away (%u). Return to Idle.", \
561  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID(), dist);
562  if (m_state != NPCAI::State::Idle) {
563  // target is no longer in npc's "sight range" and is NOT targeting this npc. unlock target and return to idle.
564  // should we do anything else here? search for another target? wander around? yes..later
565  // if npc is targeted greater than this distance, it will chase
566  ClearTarget(pSE);
567  }
568  return;
569  }
570 
571  m_isWandering = false;
572 
573  if (dist < m_flyRange) {
574  SetEngaged(pSE);
575  } else if (dist < m_boostRange) {
576  SetFollowing(pSE);
577  } else {
578  SetChasing(pSE);
579  }
580 
581  _log(NPC__AI_TRACE, "%s(%u): CheckDistance: target: %s(%u), state: %s, dist: %.0f, flyRange: %u, boostRange: %u.", \
582  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID(), GetStateName(m_state).c_str(), dist, m_flyRange, m_boostRange);
583 
584  Attack(pSE);
585 }
586 
588  if (pSE == nullptr)
589  return;
590  float targetTime = GetTargetTime();
591  bool chase = false;
592 
593  if (!m_npc->TargetMgr()->StartTargeting(pSE, targetTime, m_maxLockedTargets, m_sightRange, chase)) {
594  if (chase) {
595  _log(NPC__AI_TRACE, "%s(%u): Targeting of %s(%u) failed. Begin Chasing.", \
596  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
597  SetChasing(pSE);
598  } else {
599  _log(NPC__AI_TRACE, "%s(%u): Targeting of %s(%u) failed. Clear Target and Return to Idle.", \
600  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
601  SetIdle();
602  }
603  return;
604  }
606  CheckDistance(pSE);
607 
608  if (!m_mainAttackTimer.Enabled())
610 
611  if (!m_missileTimer.Enabled() and (m_launcherCycleTime > 100))
613 }
614 
616  if (pSE == nullptr)
617  return;
618  double targetTime = GetTargetTime();
619 
620  _log(NPC__AI_TRACE, "%s(%u): Targeted by %s(%u) while %s.", \
621  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID(), GetStateName(m_state).c_str());
622 
623  switch(m_state) {
624  case NPCAI::State::Idle: {
625  _log(NPC__AI_TRACE, "%s(%u): Begin Approaching and start Targeting sequence.", \
626  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
627  SetChasing(pSE);
628 
629  bool chase = false;
630  if (!m_npc->TargetMgr()->StartTargeting( pSE, targetTime, m_maxLockedTargets, m_sightRange, chase)) {
631  if (chase) {
632  _log(NPC__AI_TRACE, "%s(%u): Targeting of %s(%u) failed. Begin Chasing.", \
633  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
634  SetChasing(pSE);
635  } else {
636  _log(NPC__AI_TRACE, "%s(%u): Targeting of %s(%u) failed. Clear Target and Return to Idle.", \
637  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
638  SetIdle();
639  }
640  }
642  //CheckDistance(pAgressor);
643  } break;
644 
646  case NPCAI::State::Chasing: {
647  } break;
649  } break;
650  case NPCAI::State::Engaged: {
651  } break;
652  case NPCAI::State::Fleeing: {
653  } break;
655  } break;
656  }
663 }
664 
666  if (pSE == nullptr)
667  return;
668  switch(m_state) {
671  case NPCAI::State::Engaged: {
672  // implement chance for npc to follow warping player
673  // sConfig.npc.WarpFollowChance;
674  // NPCAI::State::WarpFollow
675  if (m_npc->TargetMgr()->HasNoTargets()) {
676  _log(NPC__AI_TRACE, "%s(%u): Target %s(%u) lost. No targets remain. Return to Idle.", \
677  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
678  SetIdle();
679  } else {
680  _log(NPC__AI_TRACE, "%s(%u): Target %s(%u) lost, but more targets remain.", \
681  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
684  }
685  }
686  }
687 }
688 
690 {
691  if (pSE == nullptr)
692  return;
693  if (m_mainAttackTimer.Check()) {
694  if (pSE == nullptr)
695  return;
696  // Check to see if the target still in the bubble (Client warped out)
697  if (!m_npc->SysBubble()->InBubble(pSE->GetPosition())) {
698  _log(NPC__AI_TRACE, "%s(%u): Target %s(%u) no longer in bubble. Clear target and move on",
699  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
701  ClearTarget(pSE);
702  return;
703  }
704  if (pSE->DestinyMgr() == nullptr) {
705  _log(NPC__AI_TRACE, "%s(%u): Target %s(%u) has no destiny manager. Clear target and move on",
706  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
708  ClearTarget(pSE);
709  return;
710  }
711  // Check to see if the target is not cloaked:
712  if (pSE->DestinyMgr()->IsCloaked()) {
713  _log(NPC__AI_TRACE, "%s(%u): Target %s(%u) is cloaked. Clear target and move on",
714  m_npc->GetName(), m_npc->GetID(), pSE->GetName(), pSE->GetID());
716  ClearTarget(pSE);
717  return;
718  }
719  if (m_npc->TargetMgr()->CanAttack())
720  AttackTarget(pSE);
721  }
722 }
723 
725  m_npc->TargetMgr()->ClearTarget(pSE);
726  //m_npc->TargetMgr()->OnTarget(pSE, TargMgr::Mode::Lost);
727 
728  if (m_npc->TargetMgr()->HasNoTargets())
729  SetIdle();
730 }
731 
732 //also check for special effects and write code to implement them
733 //modifyTargetSpeedRange, modifyTargetSpeedChance
734 //entityWarpScrambleChance
736  if (pSE == nullptr)
737  return;
738  // put checks here for point/tackle
739 
740  // effects are listed in EVE_Effects.h
741  std::string guid = "effects.Laser"; // client looks for 'turret' in ship.ball.modules for 'effects.laser'
742  uint32 gfxID = 0;
743  if (m_self->HasAttribute(AttrGfxTurretID))// graphicID for turret for drone type ships
746  pSE->GetID(),0,guid,1,1,
747  1,m_attackSpeed,0,gfxID);
748 
749  Damage d(m_npc,
750  m_self,
751  m_npc->GetKinetic(),
752  m_npc->GetThermal(),
753  m_npc->GetEM(),
754  m_npc->GetExplosive(),
757  );
758 
759  if (sConfig.npc.UseDamageMultiplier)
760  if (m_damageMultiplier > 0)
761  d *= m_damageMultiplier;
762 
763  pSE->ApplyDamage(d);
764 }
765 
766 /* missile shit..
767  * //AttrEntityDefenderChance - chance to shoot defender missile at incomming missile
768  * //AttrMissileLaunchDuration - missile cycle time
769  * //AttrEntityMissileTypeID
770  * //AttrMissileEntityVelocityMultiplier
771  * //AttrMissileEntityFlightTimeMultiplier
772  * //AttrMissileEntityAoeCloudSizeMultiplier
773  * //AttrMissileEntityAoeVelocityMultiplier
774  * //AttrMissileEntityAoeFalloffMultiplier
775  */
776 
778 {
779  if (typeID == 0)
780  return;
781  // Actually Launch a missile, creating a new Destiny object for it
782  // ItemData( uint32 _typeID, uint32 _ownerID, uint32 _locationID, EVEItemFlags _flag, const char *_name = "", \
783  const GPoint &_position = NULL_ORIGIN, const char *_customInfo = "", bool _contraband = false);
784  ItemData idata(typeID, m_npc->GetID(), m_npc->GetLocationID(), flagMissile, "NPC Missile", m_npc->GetPosition());
785  InventoryItemRef missileRef = sItemFactory.SpawnItem(idata);
786  if (missileRef.get() == nullptr)
787  return; // make error here
788 
789  // modify missile based on npc attribs
792  if (m_self->HasAttribute(AttrMissileEntityFlightTimeMultiplier)) // this may be wrong
800 
801  SystemManager* pSystem = m_npc->SystemMgr();
802  // Missile(InventoryItemRef self, PyServiceMgr &services, SystemManager* system, InventoryItemRef module, SystemEntity* target, ShipItem* ship);
803  Missile* pMissile = new Missile(missileRef, *(pSystem->GetServiceMgr()), pSystem, m_self, pSE, m_npc);
804  if (pMissile == nullptr)
805  return; // make error here
806  double distance = pMissile->GetPosition().distance(pSE->GetPosition());
807  double missileSpeed = missileRef->GetAttribute(AttrMaxVelocity).get_float();
808  double travelTime = (distance/missileSpeed);
809  if (travelTime < 1)
810  travelTime = 1;
811  pMissile->SetSpeed(missileSpeed);
812  pMissile->SetHitTimer(travelTime *1000);
813  pMissile->DestinyMgr()->MakeMissile(pMissile);
814 
815  // tell target a missile has been launched at them.. (defender missile trigger for ship, tower, pos, npc, others?)
816  if (typeID != 265) // but only if it's NOT a defender missile
817  pSE->MissileLaunched(pMissile);
818 }
819 
821 {
823  if (sConfig.npc.DefenderMissileChance)
824  chance = sConfig.npc.DefenderMissileChance;
825  // check chance to shoot defender missile at incomming missile (working, ??/??/??)
826  if (MakeRandomFloat() < chance)
827  LaunchMissile(265, pMissile); // defender missile
828 }
829 
831 {
832  float targetTime = (m_self->GetAttribute(AttrScanSpeed).get_float());
833  float radius = m_self->GetAttribute(AttrRadius).get_float();
834  if (targetTime < 1) {
835  if (radius < 30) {
836  targetTime = 1500;
837  } else if (radius < 60) {
838  targetTime = 2500;
839  } else if (radius < 150) {
840  targetTime = 4000;
841  } else if (radius < 280) {
842  targetTime = 6000;
843  } else if (radius < 550) {
844  targetTime = 8000;
845  } else {
846  targetTime = 13000;
847  }
848  }
849  return targetTime;
850 }
851 
852 void NPCAIMgr::DisableRepTimers(bool shield/*true*/, bool armor/*true*/)
853 {
854  if (armor)
856  if (shield)
858 }
859 
860 std::string NPCAIMgr::GetStateName(int8 stateID)
861 {
862  switch (stateID) {
863  case NPCAI::State::Idle: return "Idle";
864  case NPCAI::State::Chasing: return "Chasing";
865  case NPCAI::State::Engaged: return "Engaged";
866  case NPCAI::State::Fleeing: return "Fleeing";
867  case NPCAI::State::Following: return "Following";
868  case NPCAI::State::Signaling: return "Signaling";
869  case NPCAI::State::WarpOut: return "Warping Out";
870  case NPCAI::State::WarpFollow: return "Following Warp";
871  default: return "Invalid";
872  }
873 }
#define sConfig
A macro for easier access to the singleton.
void Target(SystemEntity *pSE)
Definition: NPCAI.cpp:587
double m_damageMultiplier
Definition: NPCAI.h:143
SystemEntity * GetSE(uint32 entityID) const
uint16 m_optimalRange
Definition: NPCAI.h:126
bool IsBelt()
Definition: SystemBubble.h:64
TurretFormulas m_formula
Definition: NPCAI.h:149
#define _log(type, fmt,...)
Definition: logsys.h:124
bool m_isWandering
Definition: NPCAI.h:108
void SetIdle()
Definition: NPCAI.cpp:446
void Disable()
Definition: timer.h:39
bool IsMission()
Definition: SystemBubble.h:67
bool IsAnomaly()
Definition: SystemBubble.h:66
uint16 m_launcherCycleTime
Definition: NPCAI.h:122
float GetTargetTime()
Definition: NPCAI.cpp:830
void UseShieldRecharge()
Definition: NPC.cpp:222
void ClearTarget(SystemEntity *tSE)
bool HasAttribute(const uint16 attrID) const
void MakeMissile(Missile *missile)
SystemBubble * SysBubble()
Definition: SystemEntity.h:195
bool InBubble(const GPoint &pt, bool inWarp=false) const
bool m_warpScram
Definition: NPCAI.h:107
void Process()
Definition: NPCAI.cpp:271
uint16 m_boostRange
Definition: NPCAI.h:127
Timer m_armorRepairTimer
Definition: NPCAI.h:155
double MakeRandomFloat(double low, double high)
Generates random real from interval [low; high].
Definition: misc.cpp:114
void SetHitTimer(uint32 setTime)
Definition: Missile.h:60
bool IsChaining(uint16 bubbleID)
Definition: SpawnMgr.cpp:827
Timer m_shieldBoosterTimer
Definition: NPCAI.h:154
bool IsFighting()
Definition: NPCAI.cpp:372
void SetMaxVelocity(float maxVelocity)
const float GetSystemSecurityRating()
Definition: SystemManager.h:86
uint32 GetRandBeltID()
void WarpOut()
Definition: NPCAI.cpp:377
InventoryItemRef m_self
Definition: NPCAI.h:147
uint16 m_orbitSpeed
Definition: NPCAI.h:124
void Attack(SystemEntity *pSE)
Definition: NPCAI.cpp:689
bool IsIncursion()
Definition: SystemBubble.h:68
TargetManager * TargetMgr()
Definition: SystemEntity.h:197
uint16 m_sigResolution
Definition: NPCAI.h:123
Timer m_mainAttackTimer
Definition: NPCAI.h:152
void SetWander()
Definition: NPCAI.cpp:409
signed __int8 int8
Definition: eve-compat.h:45
const GPoint & GetPosition() const
Definition: SystemEntity.h:211
Timer m_webifierTimer
Definition: NPCAI.h:159
void CheckDistance(SystemEntity *pSE)
Definition: NPCAI.cpp:554
uint16 m_maxSpeed
Definition: NPCAI.h:119
SystemEntity * GetRandomEntity()
void SetEngaged(SystemEntity *pSE)
Definition: NPCAI.cpp:507
uint32 m_falloff
Definition: NPCAI.h:132
Timer m_missileTimer
Definition: NPCAI.h:153
void SetFollowing(SystemEntity *pSE)
Definition: NPCAI.cpp:493
void MoveSpawn(NPC *pNPC, SystemBubble *pBubble)
Definition: SpawnMgr.cpp:141
void SendSpecialEffect(uint32 entityID, uint32 moduleID, uint32 moduleTypeID, uint32 targetID, uint32 chargeTypeID, std::string guid, bool isOffensive, bool start, bool isActive, int32 duration, uint32 repeat, int32 graphicInfo=0) const
DestinyManager * m_destiny
Definition: NPCAI.h:146
uint16 m_armorRepairDuration
Definition: NPCAI.h:128
SystemEntity * GetFirstTarget(bool need_locked=false)
DestinyManager * DestinyMgr()
Definition: SystemEntity.h:198
SystemManager * SystemMgr()
Definition: SystemEntity.h:196
SpawnMgr * GetSpawnMgr()
Definition: NPC.h:82
Timer m_beginFindTarget
Definition: NPCAI.h:156
bool Enabled() const
Definition: timer.h:41
void SetChasing(SystemEntity *pSE)
Definition: NPCAI.cpp:478
uint32 GetLocationID()
Definition: SystemEntity.h:209
uint16 GetID()
Definition: SystemBubble.h:91
uint32 get_uint32()
Definition: EvilNumber.cpp:173
Definition: Damage.h:33
uint32 PlayerCount()
uint32 m_maxAttackRange
Definition: NPCAI.h:135
bool m_useSecondTarget
Definition: NPCAI.h:111
bool m_useTargSwitching
Definition: NPCAI.h:110
uint32 GetID()
Definition: SystemEntity.h:207
NPCAIMgr(NPC *who)
Definition: NPCAI.cpp:51
bool Check(bool reset=true)
Definition: timer.cpp:62
X * get() const
Definition: RefPtr.h:213
Definition: NPC.h:41
uint16 m_shieldBoosterDuration
Definition: NPCAI.h:129
double m_trackingSpeed
Definition: NPCAI.h:142
float GetThermal()
Definition: NPC.h:76
uint8 m_maxAttackTargets
Definition: NPCAI.h:117
void SetSpeed(double speed)
Definition: Missile.h:61
float m_warpScramChance
Definition: NPCAI.h:138
const char * GetName() const
Definition: SystemEntity.h:210
bool m_webber
Definition: NPCAI.h:106
uint16 m_preferedSigRadius
Definition: NPCAI.h:114
float m_armorRepairDelayChance
Definition: NPCAI.h:139
float GetExplosive()
Definition: NPC.h:79
uint16 m_attackSpeed
Definition: NPCAI.h:120
unsigned __int32 uint32
Definition: eve-compat.h:50
NPC * m_npc
Definition: NPCAI.h:145
PyServiceMgr * GetServiceMgr()
Definition: SystemManager.h:88
Definition: NPCAI.h:33
void MissileLaunched(Missile *pMissile)
Definition: NPCAI.cpp:820
void Follow(SystemEntity *pSE, uint32 distance)
void TargetLost(SystemEntity *pSE)
Definition: NPCAI.cpp:665
bool HasDynamics() const
Definition: SystemBubble.h:87
void GotoPoint(const GPoint &point)
void DisableRepTimers(bool shield=true, bool armor=true)
Definition: NPCAI.cpp:852
Timer m_warpScramblerTimer
Definition: NPCAI.h:158
uint32 m_sigRadius
Definition: NPCAI.h:131
void WarpTo(const GPoint &where, int32 distance=0, bool autoPilot=false, SystemEntity *pSE=nullptr)
float m_switchTargChance
Definition: NPCAI.h:113
int64 MakeRandomInt(int64 low, int64 high)
Generates random integer from interval [low; high].
Definition: misc.cpp:109
bool HasNoTargets() const
void UseArmorRepairer()
Definition: NPC.cpp:238
void Orbit(SystemEntity *pSE, uint32 distance=0)
EvilNumber GetAttribute(const uint16 attrID) const
uint32 m_flyRange
Definition: NPCAI.h:133
void LaunchMissile(uint16 typeID, SystemEntity *pSE)
Definition: NPCAI.cpp:777
double get_double()
Definition: EvilNumber.cpp:191
std::string GetStateName(int8 stateID)
Definition: NPCAI.cpp:860
uint32 m_sightRange
Definition: NPCAI.h:134
void AttackTarget(SystemEntity *pSE)
Definition: NPCAI.cpp:735
#define sItemFactory
Definition: ItemFactory.h:165
float get_float()
Definition: EvilNumber.cpp:184
uint8 m_maxLockedTargets
Definition: NPCAI.h:118
void SetSignaling(SystemEntity *pSE)
Definition: NPCAI.cpp:538
GaExpInl GaFloat distance(const GaVec3 &oth) const
Definition: GaTypes.h:158
virtual void MissileLaunched(Missile *pMissile)
Definition: SystemEntity.h:249
void Targeted(SystemEntity *pSE)
Definition: NPCAI.cpp:615
float GetNPCToHit(NPC *pNPC, SystemEntity *pTarget)
float GetEM()
Definition: NPC.h:77
bool m_useSigRadius
Definition: NPCAI.h:109
#define sBubbleMgr
bool ApplyDamage(Damage &d)
Definition: Damage.cpp:108
unsigned __int16 uint16
Definition: eve-compat.h:48
Timer m_warpOutTimer
Definition: NPCAI.h:157
uint16 typeID() const
bool IsTargetedBy(SystemEntity *pSE)
float GetKinetic()
Definition: NPC.h:78
void ClearTarget(SystemEntity *pSE)
Definition: NPCAI.cpp:724
int8 m_state
Definition: NPCAI.h:101
void SetFleeing(SystemEntity *pSE)
Definition: NPCAI.cpp:522
bool StartTargeting(SystemEntity *tSE, ShipItemRef sRef)
uint32 itemID() const
Definition: InventoryItem.h:98
void GetPlayers(std::vector< Client * > &into) const
uint32 m_warpScramRange
Definition: NPCAI.h:136
uint16 m_missileTypeID
Definition: NPCAI.h:121
float m_shieldBoosterDelayChance
Definition: NPCAI.h:140
void Start(uint32 setTimerTime=0, bool changeResetTimer=true)
Definition: timer.cpp:81