diff options
Diffstat (limited to 'src/server/game/AI/SmartScripts')
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.cpp | 399 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.h | 70 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 29 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.cpp | 59 | ||||
| -rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 39 | 
5 files changed, 260 insertions, 336 deletions
| diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 71cb6f7fdad..58f8f72d47b 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -17,6 +17,7 @@  #include "SmartAI.h"  #include "Creature.h" +#include "CreatureGroups.h"  #include "DBCStructure.h"  #include "GameObject.h"  #include "Group.h" @@ -28,54 +29,12 @@  #include "ScriptMgr.h"  #include "Vehicle.h" -SmartAI::SmartAI(Creature* c) : CreatureAI(c) +SmartAI::SmartAI(Creature* creature) : CreatureAI(creature), mIsCharmed(false), mFollowCreditType(0), mFollowArrivedTimer(0), mFollowCredit(0), mFollowArrivedEntry(0), mFollowDist(0.f), mFollowAngle(0.f), +    _escortState(SMART_ESCORT_NONE), _escortNPCFlags(0), _escortInvokerCheckTimer(1000), _currentWaypointNode(0), _waypointReached(false), _waypointPauseTimer(0), _waypointPauseForced(false), _repeatWaypointPath(false), +    _OOCReached(false), _waypointPathEnded(false), mRun(true), mEvadeDisabled(false), mCanAutoAttack(true), mCanCombatMove(true), mInvincibilityHpLevel(0), mDespawnTime(0), mDespawnState(0), mJustReset(false), +    mConditionsTimer(0), _gossipReturn(false)  { -    mIsCharmed = false; -    // copy script to local (protection for table reload) - -    mWayPoints = nullptr; -    mEscortState = SMART_ESCORT_NONE; -    mCurrentWPID = 0;//first wp id is 1 !! -    mWPReached = false; -    mWPPauseTimer = 0; -    mEscortNPCFlags = 0; -    mLastWP = nullptr; - -    mCanRepeatPath = false; - -    // Spawn in run mode -    me->SetWalk(false); -    mRun = false; -    mEvadeDisabled = false; - -    mLastOOCPos = me->GetPosition(); - -    mCanAutoAttack = true; -    mCanCombatMove = true; - -    mForcedPaused = false; -    mLastWPIDReached = 0; - -    mEscortQuestID = 0; - -    mDespawnTime = 0; -    mDespawnState = 0; - -    mEscortInvokerCheckTimer = 1000; -    mFollowGuid.Clear(); -    mFollowDist = 0; -    mFollowAngle = 0; -    mFollowCredit = 0; -    mFollowArrivedEntry = 0; -    mFollowCreditType = 0; -    mFollowArrivedTimer = 0; -    mInvincibilityHpLevel = 0; - -    mJustReset = false; -    mConditionsTimer = 0; -    mHasConditions = sConditionMgr->HasConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, c->GetEntry()); - -    _gossipReturn = false; +    mHasConditions = sConditionMgr->HasConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, creature->GetEntry());  }  bool SmartAI::IsAIControlled() const @@ -101,74 +60,68 @@ void SmartAI::UpdateDespawn(uint32 diff)      } else mDespawnTime -= diff;  } -WayPoint* SmartAI::GetNextWayPoint() +void SmartAI::StartPath(bool run/* = false*/, uint32 pathId/* = 0*/, bool repeat/* = false*/, Unit* invoker/* = nullptr*/, uint32 nodeId/* = 1*/)  { -    if (!mWayPoints || mWayPoints->empty()) -        return nullptr; - -    mCurrentWPID++; -    WPPath::const_iterator itr = mWayPoints->find(mCurrentWPID); -    if (itr != mWayPoints->end()) +    if (me->IsInCombat()) // no wp movement in combat      { -        mLastWP = (*itr).second; -        if (mLastWP->id != mCurrentWPID) -        { -            TC_LOG_ERROR("misc", "SmartAI::GetNextWayPoint: Got not expected waypoint id %u, expected %u", mLastWP->id, mCurrentWPID); -        } -        return (*itr).second; -    } -    return nullptr; -} - -void SmartAI::StartPath(bool run, uint32 path, bool repeat, Unit* invoker) -{ -    if (me->IsInCombat())// no wp movement in combat -    { -        TC_LOG_ERROR("misc", "SmartAI::StartPath: Creature entry %u wanted to start waypoint movement while in combat, ignoring.", me->GetEntry()); +        TC_LOG_ERROR("misc", "SmartAI::StartPath: Creature entry %u wanted to start waypoint movement (%u) while in combat, ignoring.", me->GetEntry(), pathId);          return;      }      if (HasEscortState(SMART_ESCORT_ESCORTING))          StopPath(); -    if (path) +    SetRun(run); + +    if (pathId)      { -        if (!LoadPath(path)) +        if (!LoadPath(pathId))              return;      } -    if (!mWayPoints || mWayPoints->empty()) +    if (_path.nodes.empty())          return; -    if (WayPoint* wp = GetNextWayPoint()) -    { -        AddEscortState(SMART_ESCORT_ESCORTING); -        mCanRepeatPath = repeat; +    _currentWaypointNode = nodeId; +    _waypointPathEnded = false; -        SetRun(run); +    _repeatWaypointPath = repeat; -        if (invoker && invoker->GetTypeId() == TYPEID_PLAYER) -        { -            mEscortNPCFlags = me->GetUInt32Value(UNIT_NPC_FLAGS); -            me->SetUInt32Value(UNIT_NPC_FLAGS, 0); -        } +    // Do not use AddEscortState, removing everything from previous +    _escortState = SMART_ESCORT_ESCORTING; -        mLastOOCPos = me->GetPosition(); -        me->GetMotionMaster()->MovePoint(wp->id, wp->x, wp->y, wp->z); -        GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_START, nullptr, wp->id, GetScript()->GetPathId()); +    if (invoker && invoker->GetTypeId() == TYPEID_PLAYER) +    { +        _escortNPCFlags = me->GetUInt32Value(UNIT_NPC_FLAGS); +        me->SetFlag(UNIT_NPC_FLAGS, 0);      } + +    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_START, nullptr, _currentWaypointNode, GetScript()->GetPathId()); + +    me->GetMotionMaster()->MovePath(_path, _repeatWaypointPath);  }  bool SmartAI::LoadPath(uint32 entry)  {      if (HasEscortState(SMART_ESCORT_ESCORTING))          return false; -    mWayPoints = sSmartWaypointMgr->GetPath(entry); -    if (!mWayPoints) + +    WaypointPath const* path = sSmartWaypointMgr->GetPath(entry); +    if (!path || path->nodes.empty())      {          GetScript()->SetPathId(0);          return false;      } + +    _path.id = path->id; +    _path.nodes = path->nodes; +    for (WaypointNode& waypoint : _path.nodes) +    { +        Trinity::NormalizeMapCoord(waypoint.x); +        Trinity::NormalizeMapCoord(waypoint.y); +        waypoint.moveType = mRun ? WAYPOINT_MOVE_TYPE_RUN : WAYPOINT_MOVE_TYPE_WALK; +    } +      GetScript()->SetPathId(entry);      return true;  } @@ -177,22 +130,26 @@ void SmartAI::PausePath(uint32 delay, bool forced)  {      if (!HasEscortState(SMART_ESCORT_ESCORTING))          return; +      if (HasEscortState(SMART_ESCORT_PAUSED))      { -        TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint movement while already paused, ignoring.", me->GetEntry()); +        TC_LOG_ERROR("misc", "SmartAI::PausePath: Creature entry %u wanted to pause waypoint (current waypoint: %u) movement while already paused, ignoring.", me->GetEntry(), _currentWaypointNode);          return;      } -    mForcedPaused = forced; -    mLastOOCPos = me->GetPosition(); -    AddEscortState(SMART_ESCORT_PAUSED); -    mWPPauseTimer = delay; + +    _waypointPauseTimer = delay; +      if (forced)      { +        _waypointPauseForced = forced;          SetRun(mRun); -        me->StopMoving();//force stop -        me->GetMotionMaster()->MoveIdle();//force stop +        me->PauseMovement();      } -    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, mLastWP->id, GetScript()->GetPathId()); +    else +        _waypointReached = false; + +    AddEscortState(SMART_ESCORT_PAUSED); +    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_PAUSED, nullptr, _currentWaypointNode, GetScript()->GetPathId());  }  void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail) @@ -202,40 +159,29 @@ void SmartAI::StopPath(uint32 DespawnTime, uint32 quest, bool fail)      if (quest)          mEscortQuestID = quest; -    SetDespawnTime(DespawnTime); -    //mDespawnTime = DespawnTime; -    mLastOOCPos = me->GetPosition(); -    me->StopMoving();//force stop +    if (mDespawnState != 2) +        SetDespawnTime(DespawnTime); +      me->GetMotionMaster()->MoveIdle(); -    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, mLastWP->id, GetScript()->GetPathId()); + +    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_STOPPED, nullptr, _currentWaypointNode, GetScript()->GetPathId()); +      EndPath(fail);  }  void SmartAI::EndPath(bool fail)  { -    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, mLastWP->id, GetScript()->GetPathId()); -      RemoveEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING); -    mWayPoints = nullptr; -    mCurrentWPID = 0; -    mWPPauseTimer = 0; -    mLastWP = nullptr; +    _path.nodes.clear(); +    _waypointPauseTimer = 0; -    if (mEscortNPCFlags) +    if (_escortNPCFlags)      { -        me->SetUInt32Value(UNIT_NPC_FLAGS, mEscortNPCFlags); -        mEscortNPCFlags = 0; +        me->SetFlag(UNIT_NPC_FLAGS, _escortNPCFlags); +        _escortNPCFlags = 0;      } -    if (mCanRepeatPath) -    { -        if (IsAIControlled()) -            StartPath(mRun, GetScript()->GetPathId(), true); -    } -    else -        GetScript()->SetPathId(0); -      ObjectVector const* targets = GetScript()->GetStoredTargetVector(SMART_ESCORT_TARGETS, *me);      if (targets && mEscortQuestID)      { @@ -279,15 +225,36 @@ void SmartAI::EndPath(bool fail)          }      } +    // End Path events should be only processed if it was SUCCESSFUL stop or stop called by SMART_ACTION_WAYPOINT_STOP +    if (fail) +        return; + +    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_ENDED, nullptr, _currentWaypointNode, GetScript()->GetPathId()); + +    if (_repeatWaypointPath) +    { +        if (IsAIControlled()) +            StartPath(mRun, GetScript()->GetPathId(), _repeatWaypointPath); +    } +    else +        GetScript()->SetPathId(0); +      if (mDespawnState == 1)          StartDespawn();  }  void SmartAI::ResumePath()  { +    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, nullptr, _currentWaypointNode, GetScript()->GetPathId()); + +    RemoveEscortState(SMART_ESCORT_PAUSED); + +    _waypointPauseForced = false; +    _waypointReached = false; +    _waypointPauseTimer = 0; +      SetRun(mRun); -    if (mLastWP) -        me->GetMotionMaster()->MovePoint(mLastWP->id, mLastWP->x, mLastWP->y, mLastWP->z); +    me->ResumeMovement();  }  void SmartAI::ReturnToLastOOCPos() @@ -295,82 +262,57 @@ void SmartAI::ReturnToLastOOCPos()      if (!IsAIControlled())          return; -    SetRun(mRun); -    me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, mLastOOCPos); +    me->SetWalk(false); +    me->GetMotionMaster()->MovePoint(SMART_ESCORT_LAST_OOC_POINT, me->GetHomePosition());  }  void SmartAI::UpdatePath(const uint32 diff)  {      if (!HasEscortState(SMART_ESCORT_ESCORTING))          return; -    if (mEscortInvokerCheckTimer < diff) + +    if (_escortInvokerCheckTimer < diff)      { -        // Escort failed, no players in range          if (!IsEscortInvokerInRange())          {              StopPath(0, mEscortQuestID, true);              // allow to properly hook out of range despawn action, which in most cases should perform the same operation as dying              GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, me); -            me->DespawnOrUnsummon(1); +            me->DespawnOrUnsummon();              return;          } -        mEscortInvokerCheckTimer = 1000; +        _escortInvokerCheckTimer = 1000;      }      else -        mEscortInvokerCheckTimer -= diff; +        _escortInvokerCheckTimer -= diff;      // handle pause -    if (HasEscortState(SMART_ESCORT_PAUSED)) +    if (HasEscortState(SMART_ESCORT_PAUSED) && (_waypointReached || _waypointPauseForced))      { -        if (mWPPauseTimer < diff) +        if (_waypointPauseTimer <= diff)          { -            if (!me->IsInCombat() && !HasEscortState(SMART_ESCORT_RETURNING) && (mWPReached || mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT || mForcedPaused)) -            { -                GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_RESUMED, nullptr, mLastWP->id, GetScript()->GetPathId()); -                RemoveEscortState(SMART_ESCORT_PAUSED); -                if (mForcedPaused)// if paused between 2 wps resend movement -                { -                    ResumePath(); -                    mWPReached = false; -                    mForcedPaused = false; -                } -                if (mLastWPIDReached == SMART_ESCORT_LAST_OOC_POINT) -                    mWPReached = true; -            } - -            mWPPauseTimer = 0; +            if (!me->IsInCombat() && !HasEscortState(SMART_ESCORT_RETURNING)) +                ResumePath();          }          else -            mWPPauseTimer -= diff; +            _waypointPauseTimer -= diff; +    } +    else if (_waypointPathEnded) // end path +    { +        _waypointPathEnded = false; +        StopPath(); +        return;      }      if (HasEscortState(SMART_ESCORT_RETURNING))      { -        if (mWPReached)//reached OOC WP +        if (_OOCReached) // reached OOC WP          { +            _OOCReached = false;              RemoveEscortState(SMART_ESCORT_RETURNING);              if (!HasEscortState(SMART_ESCORT_PAUSED))                  ResumePath(); -            mWPReached = false; -        } -    } - -    if ((!me->HasReactState(REACT_PASSIVE) && me->IsInCombat()) || HasEscortState(SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING)) -        return; - -    // handle next wp -    if (mWPReached)//reached WP -    { -        mWPReached = false; -        if (mCurrentWPID == GetWPCount()) -        { -            EndPath(); -        } -        else if (WayPoint* wp = GetNextWayPoint()) -        { -            SetRun(mRun); -            me->GetMotionMaster()->MovePoint(wp->id, wp->x, wp->y, wp->z);          }      }  } @@ -450,24 +392,43 @@ bool SmartAI::IsEscortInvokerInRange()      return true;  } -void SmartAI::MovepointReached(uint32 id) +///@todo Implement new smart event SMART_EVENT_WAYPOINT_STARTED +void SmartAI::WaypointStarted(uint32 /*nodeId*/, uint32 /*pathId*/)  { -    if (id != SMART_ESCORT_LAST_OOC_POINT && mLastWPIDReached != id) -        GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, id); +} + +void SmartAI::WaypointReached(uint32 nodeId, uint32 pathId) +{ +    _currentWaypointNode = nodeId; + +    GetScript()->ProcessEventsFor(SMART_EVENT_WAYPOINT_REACHED, nullptr, _currentWaypointNode, pathId); -    mLastWPIDReached = id; -    mWPReached = true; +    if (_waypointPauseTimer && !_waypointPauseForced) +    { +        _waypointReached = true; +        me->PauseMovement(); +    } +    else if (HasEscortState(SMART_ESCORT_ESCORTING) && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) +    { +        if (_currentWaypointNode == _path.nodes.size()) +            _waypointPathEnded = true; +        else +            SetRun(mRun); +    }  } -void SmartAI::MovementInform(uint32 MovementType, uint32 Data) +void SmartAI::MovementInform(uint32 type, uint32 id)  { -    if ((MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT) || MovementType == FOLLOW_MOTION_TYPE) +    if (type == POINT_MOTION_TYPE && id == SMART_ESCORT_LAST_OOC_POINT)          me->ClearUnitState(UNIT_STATE_EVADE); -    GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, nullptr, MovementType, Data); -    if (MovementType != POINT_MOTION_TYPE || !HasEscortState(SMART_ESCORT_ESCORTING)) +    GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, nullptr, type, id); + +    if (!HasEscortState(SMART_ESCORT_ESCORTING))          return; -    MovepointReached(Data); + +    if (type == POINT_MOTION_TYPE && id == SMART_ESCORT_LAST_OOC_POINT) +        _OOCReached = true;  }  void SmartAI::EnterEvadeMode(EvadeReason /*why*/) @@ -511,8 +472,8 @@ void SmartAI::EnterEvadeMode(EvadeReason /*why*/)      else          me->GetMotionMaster()->MoveTargetedHome(); -    if (!HasEscortState(SMART_ESCORT_ESCORTING)) //dont mess up escort movement after combat -        SetRun(mRun); +    if (!me->HasUnitState(UNIT_STATE_EVADE)) +        GetScript()->OnReset();  }  void SmartAI::MoveInLineOfSight(Unit* who) @@ -544,19 +505,19 @@ bool SmartAI::AssistPlayerInCombatAgainst(Unit* who)      if (!who || !who->GetVictim())          return false; -    //experimental (unknown) flag not present +    // experimental (unknown) flag not present      if (!(me->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST))          return false; -    //not a player +    // not a player      if (!who->EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself())          return false; -    //never attack friendly +    // never attack friendly      if (!me->IsValidAssistTarget(who->GetVictim()))          return false; -    //too far away and no free sight? +    // too far away and no free sight?      if (me->IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me->IsWithinLOSInMap(who))      {          me->EngageWithTarget(who); @@ -570,14 +531,14 @@ void SmartAI::JustAppeared()  {      mDespawnTime = 0;      mDespawnState = 0; -    mEscortState = SMART_ESCORT_NONE; +    _escortState = SMART_ESCORT_NONE;      me->SetVisible(true);      if (me->GetFaction() != me->GetCreatureTemplate()->faction)          me->RestoreFaction();      mJustReset = true;      JustReachedHome();      GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN); -    mFollowGuid.Clear();//do not reset follower on Reset(), we need it after combat evade +    mFollowGuid.Clear(); // do not reset follower on Reset(), we need it after combat evade      mFollowDist = 0;      mFollowAngle = 0;      mFollowCredit = 0; @@ -594,8 +555,16 @@ void SmartAI::JustReachedHome()      {          GetScript()->ProcessEventsFor(SMART_EVENT_REACHED_HOME); -        if (!UpdateVictim() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE && me->GetWaypointPath()) -            me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true); +        CreatureGroup* formation = me->GetFormation(); +        if (!formation || formation->getLeader() == me || !formation->isFormed()) +        { +            if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE && me->GetWaypointPath()) +                me->GetMotionMaster()->MovePath(me->GetWaypointPath(), true); +            else +                me->ResumeMovement(); +        } +        else if (formation->isFormed()) +            me->GetMotionMaster()->MoveIdle(); // wait the order of leader      }      mJustReset = false; @@ -607,24 +576,14 @@ void SmartAI::EnterCombat(Unit* enemy)          me->InterruptNonMeleeSpells(false); // must be before ProcessEvents      GetScript()->ProcessEventsFor(SMART_EVENT_AGGRO, enemy); - -    if (!IsAIControlled()) -        return; -    mLastOOCPos = me->GetPosition(); -    SetRun(mRun); -    if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == POINT_MOTION_TYPE) -        me->GetMotionMaster()->MovementExpired();  }  void SmartAI::JustDied(Unit* killer)  { -    GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, killer);      if (HasEscortState(SMART_ESCORT_ESCORTING)) -    {          EndPath(true); -        me->StopMoving();//force stop -        me->GetMotionMaster()->MoveIdle(); -    } + +    GetScript()->ProcessEventsFor(SMART_EVENT_DEATH, killer);  }  void SmartAI::KilledUnit(Unit* victim) @@ -642,15 +601,21 @@ void SmartAI::AttackStart(Unit* who)      // dont allow charmed npcs to act on their own      if (!IsAIControlled())      { -        if (who && mCanAutoAttack) -            me->Attack(who, true); +        if (who) +            me->Attack(who, mCanAutoAttack);          return;      } -    if (who && me->Attack(who, me->IsWithinMeleeRange(who))) +    if (who && me->Attack(who, mCanAutoAttack))      { +        me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); +        me->PauseMovement(); +          if (mCanCombatMove) +        { +            SetRun(mRun);              me->GetMotionMaster()->MoveChase(who); +        }      }  } @@ -713,10 +678,10 @@ void SmartAI::PassengerBoarded(Unit* who, int8 seatId, bool apply)  void SmartAI::InitializeAI()  {      GetScript()->OnInitialize(me); +      if (!me->isDead())      { -        mJustReset = true; -        JustReachedHome(); +        GetScript()->OnReset();          GetScript()->ProcessEventsFor(SMART_EVENT_RESPAWN);      }  } @@ -727,13 +692,13 @@ void SmartAI::OnCharmed(bool apply)      {          if (HasEscortState(SMART_ESCORT_ESCORTING | SMART_ESCORT_PAUSED | SMART_ESCORT_RETURNING))              EndPath(true); -        me->StopMoving();      } +      mIsCharmed = apply;      if (!apply && !me->IsInEvadeMode())      { -        if (mCanRepeatPath) +        if (_repeatWaypointPath)              StartPath(mRun, GetScript()->GetPathId(), true);          else              me->SetWalk(!mRun); @@ -826,30 +791,21 @@ void SmartAI::SetCombatMove(bool on)  {      if (mCanCombatMove == on)          return; +      mCanCombatMove = on; +      if (!IsAIControlled())          return; -    if (!HasEscortState(SMART_ESCORT_ESCORTING)) + +    if (me->IsEngaged())      { -        if (on && me->GetVictim()) +        if (on && !me->HasReactState(REACT_PASSIVE) && me->GetVictim() && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == MAX_MOTION_TYPE)          { -            if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE) -            { -                SetRun(mRun); -                me->GetMotionMaster()->MoveChase(me->GetVictim()); -                me->CastStop(); -            } -        } -        else -        { -            if (me->HasUnitState(UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE)) -                return; - -            me->GetMotionMaster()->MovementExpired(); -            me->GetMotionMaster()->Clear(true); -            me->StopMoving(); -            me->GetMotionMaster()->MoveIdle(); +            SetRun(mRun); +            me->GetMotionMaster()->MoveChase(me->GetVictim());          } +        else if (!on && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == CHASE_MOTION_TYPE) +            me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE);      }  } @@ -881,7 +837,6 @@ void SmartAI::StopFollow(bool complete)      mFollowArrivedTimer = 1000;      mFollowArrivedEntry = 0;      mFollowCreditType = 0; -    me->StopMoving();      me->GetMotionMaster()->MoveIdle();      if (!complete) diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 3834fd01d07..9c22b509bc9 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -23,8 +23,7 @@  #include "GameObjectAI.h"  #include "Position.h"  #include "SmartScript.h" - -struct WayPoint; +#include "WaypointDefines.h"  enum SmartEscortState  { @@ -43,32 +42,37 @@ enum SmartEscortVars  class TC_GAME_API SmartAI : public CreatureAI  {      public: -        ~SmartAI(){ } +        ~SmartAI() { }          explicit SmartAI(Creature* c); +        // core related +        static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } +          // Check whether we are currently permitted to make the creature take action          bool IsAIControlled() const;          // Start moving to the desired MovePoint -        void StartPath(bool run = false, uint32 path = 0, bool repeat = false, Unit* invoker = nullptr); +        void StartPath(bool run = false, uint32 pathId = 0, bool repeat = false, Unit* invoker = nullptr, uint32 nodeId = 1);          bool LoadPath(uint32 entry);          void PausePath(uint32 delay, bool forced = false);          void StopPath(uint32 DespawnTime = 0, uint32 quest = 0, bool fail = false);          void EndPath(bool fail = false);          void ResumePath(); -        WayPoint* GetNextWayPoint(); -        bool HasEscortState(uint32 uiEscortState) const { return (mEscortState & uiEscortState) != 0; } -        void AddEscortState(uint32 uiEscortState) { mEscortState |= uiEscortState; } -        void RemoveEscortState(uint32 uiEscortState) { mEscortState &= ~uiEscortState; } +        bool HasEscortState(uint32 uiEscortState) const { return (_escortState & uiEscortState) != 0; } +        void AddEscortState(uint32 uiEscortState) { _escortState |= uiEscortState; } +        void RemoveEscortState(uint32 uiEscortState) { _escortState &= ~uiEscortState; }          void SetAutoAttack(bool on) { mCanAutoAttack = on; }          void SetCombatMove(bool on);          bool CanCombatMove() { return mCanCombatMove; }          void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0);          void StopFollow(bool complete); +        bool IsEscortInvokerInRange(); + +        void WaypointStarted(uint32 nodeId, uint32 pathId) override; +        void WaypointReached(uint32 nodeId, uint32 pathId) override;          void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker);          SmartScript* GetScript() { return &mScript; } -        bool IsEscortInvokerInRange();          // Called when creature is spawned or respawned          void JustAppeared() override; @@ -157,12 +161,6 @@ class TC_GAME_API SmartAI : public CreatureAI          // Used in scripts to share variables          ObjectGuid GetGUID(int32 id = 0) const override; -        //core related -        static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } - -        // Called at movepoint reached -        void MovepointReached(uint32 id); -          // Makes the creature run/walk          void SetRun(bool run = true); @@ -194,11 +192,20 @@ class TC_GAME_API SmartAI : public CreatureAI          void OnSpellClick(Unit* clicker, bool& result) override; -        void SetWPPauseTimer(uint32 time) { mWPPauseTimer = time; } +        void SetWPPauseTimer(uint32 time) { _waypointPauseTimer = time; }          void SetGossipReturn(bool val) { _gossipReturn = val; }      private: +        bool AssistPlayerInCombatAgainst(Unit* who); +        void ReturnToLastOOCPos(); +        void UpdatePath(const uint32 diff); +        void UpdateDespawn(uint32 diff); +        // Vehicle conditions +        void CheckConditions(uint32 diff); + +        SmartScript mScript; +          bool mIsCharmed;          uint32 mFollowCreditType;          uint32 mFollowArrivedTimer; @@ -208,36 +215,29 @@ class TC_GAME_API SmartAI : public CreatureAI          float mFollowDist;          float mFollowAngle; -        void ReturnToLastOOCPos(); -        void UpdatePath(const uint32 diff); -        SmartScript mScript; -        WPPath* mWayPoints; -        uint32 mEscortState; -        uint32 mCurrentWPID; -        uint32 mLastWPIDReached; -        bool mWPReached; -        uint32 mWPPauseTimer; -        uint32 mEscortNPCFlags; -        WayPoint* mLastWP; -        Position mLastOOCPos;//set on enter combat -        uint32 GetWPCount() const { return mWayPoints ? uint32(mWayPoints->size()) : 0; } -        bool mCanRepeatPath; +        uint32 _escortState; +        uint32 _escortNPCFlags; +        uint32 _escortInvokerCheckTimer; +        WaypointPath _path; +        uint32 _currentWaypointNode; +        bool _waypointReached; +        uint32 _waypointPauseTimer; +        bool _waypointPauseForced; +        bool _repeatWaypointPath; +        bool _OOCReached; +        bool _waypointPathEnded; +          bool mRun;          bool mEvadeDisabled;          bool mCanAutoAttack;          bool mCanCombatMove; -        bool mForcedPaused;          uint32 mInvincibilityHpLevel; -        bool AssistPlayerInCombatAgainst(Unit* who);          uint32 mDespawnTime;          uint32 mDespawnState; -        void UpdateDespawn(uint32 diff); -        uint32 mEscortInvokerCheckTimer;          bool mJustReset;          // Vehicle conditions -        void CheckConditions(uint32 diff);          bool mHasConditions;          uint32 mConditionsTimer; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 79f3b7ce652..7f002ed6671 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -39,6 +39,7 @@  #include "SpellMgr.h"  #include "TemporarySummon.h"  #include "Vehicle.h" +#include "WaypointDefines.h"  #include <G3D/Quat.h>  SmartScript::SmartScript() @@ -1990,7 +1991,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u                  std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });              float distanceToClosest = std::numeric_limits<float>::max(); -            WayPoint* closestWp = nullptr; +            std::pair<uint32, uint32> closest = { 0, 0 };              for (WorldObject* target : targets)              { @@ -1998,29 +1999,27 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u                  {                      if (IsSmart(creature))                      { -                        for (uint32 wp : waypoints) +                        for (uint32 pathId : waypoints)                          { -                            WPPath* path = sSmartWaypointMgr->GetPath(wp); -                            if (!path || path->empty()) +                            WaypointPath const* path = sSmartWaypointMgr->GetPath(pathId); +                            if (!path || path->nodes.empty())                                  continue; -                            auto itrWp = path->find(0); -                            if (itrWp != path->end()) +                            for (auto itr = path->nodes.begin(); itr != path->nodes.end(); ++itr)                              { -                                if (WayPoint* wp = itrWp->second) +                                WaypointNode const waypoint = *itr; +                                float distamceToThisNode = creature->GetDistance(waypoint.x, waypoint.y, waypoint.z); +                                if (distamceToThisNode < distanceToClosest)                                  { -                                    float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z); -                                    if (distToThisPath < distanceToClosest) -                                    { -                                        distanceToClosest = distToThisPath; -                                        closestWp = wp; -                                    } +                                    distanceToClosest = distamceToThisNode; +                                    closest.first = pathId; +                                    closest.second = waypoint.id;                                  }                              }                          } -                        if (closestWp) -                            CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true); +                        if (closest.first != 0) +                            CAST_AI(SmartAI, creature->AI())->StartPath(false, closest.first, true, nullptr, closest.second);                      }                  }              } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 3555575b2b2..b4713b7ed4d 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -29,6 +29,7 @@  #include "SpellMgr.h"  #include "Timer.h"  #include "UnitDefines.h" +#include "WaypointDefines.h"  SmartWaypointMgr* SmartWaypointMgr::instance()  { @@ -40,15 +41,7 @@ void SmartWaypointMgr::LoadFromDB()  {      uint32 oldMSTime = getMSTime(); -    for (std::unordered_map<uint32, WPPath*>::iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr) -    { -        for (WPPath::iterator pathItr = itr->second->begin(); pathItr != itr->second->end(); ++pathItr) -            delete pathItr->second; - -        delete itr->second; -    } - -    waypoint_map.clear(); +    _waypointStore.clear();      PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_SMARTAI_WP);      PreparedQueryResult result = WorldDatabase.Query(stmt); @@ -62,50 +55,47 @@ void SmartWaypointMgr::LoadFromDB()      uint32 count = 0;      uint32 total = 0; -    uint32 last_entry = 0; -    uint32 last_id = 1; +    uint32 lastEntry = 0; +    uint32 lastId = 1;      do      {          Field* fields = result->Fetch();          uint32 entry = fields[0].GetUInt32();          uint32 id = fields[1].GetUInt32(); -        float x, y, z; -        x = fields[2].GetFloat(); -        y = fields[3].GetFloat(); -        z = fields[4].GetFloat(); +        float x = fields[2].GetFloat(); +        float y = fields[3].GetFloat(); +        float z = fields[4].GetFloat(); -        if (last_entry != entry) +        if (lastEntry != entry)          { -            waypoint_map[entry] = new WPPath(); -            last_id = 1; -            count++; +            lastId = 1; +            ++count;          } -        if (last_id != id) -            TC_LOG_ERROR("sql.sql", "SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u.", entry, id, last_id); +        if (lastId != id) +            TC_LOG_ERROR("sql.sql", "SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u.", entry, id, lastId); -        last_id++; -        (*waypoint_map[entry])[id] = new WayPoint(id, x, y, z); +        ++lastId; +        WaypointPath& path = _waypointStore[entry]; +        path.id = entry; +        path.nodes.emplace_back(id, x, y, z); -        last_entry = entry; -        total++; +        lastEntry = entry; +        ++total;      }      while (result->NextRow());      TC_LOG_INFO("server.loading", ">> Loaded %u SmartAI waypoint paths (total %u waypoints) in %u ms", count, total, GetMSTimeDiffToNow(oldMSTime));  } -SmartWaypointMgr::~SmartWaypointMgr() +WaypointPath const* SmartWaypointMgr::GetPath(uint32 id)  { -    for (std::unordered_map<uint32, WPPath*>::iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr) -    { -        for (WPPath::iterator pathItr = itr->second->begin(); pathItr != itr->second->end(); ++pathItr) -            delete pathItr->second; - -        delete itr->second; -    } +    auto itr = _waypointStore.find(id); +    if (itr != _waypointStore.end()) +        return &itr->second; +    return nullptr;  }  SmartAIMgr* SmartAIMgr::instance() @@ -1314,7 +1304,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)              break;          case SMART_ACTION_WP_START:          { -            if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID)) +            WaypointPath const* path = sSmartWaypointMgr->GetPath(e.action.wpStart.pathID); +            if (!path || path->nodes.empty())              {                  TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature %d Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID);                  return false; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index f2ba244aaae..747b3c3d2c4 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -20,6 +20,7 @@  #include "Define.h"  #include "ObjectGuid.h" +#include "WaypointDefines.h"  #include <map>  #include <string>  #include <unordered_map> @@ -27,22 +28,6 @@  class WorldObject;  enum SpellEffIndex : uint8; -struct WayPoint -{ -    WayPoint(uint32 _id, float _x, float _y, float _z) -    { -        id = _id; -        x = _x; -        y = _y; -        z = _z; -    } - -    uint32 id; -    float x; -    float y; -    float z; -}; -  enum eSmartAI  {      SMART_EVENT_PARAM_COUNT = 4, @@ -1514,8 +1499,6 @@ struct SmartScriptHolder      operator bool() const { return entryOrGuid != 0; }  }; -typedef std::unordered_map<uint32, WayPoint*> WPPath; -  typedef std::vector<WorldObject*> ObjectVector;  class ObjectGuidVector @@ -1542,26 +1525,22 @@ typedef std::unordered_map<uint32, ObjectGuidVector> ObjectVectorMap;  class TC_GAME_API SmartWaypointMgr  { -    private: -        SmartWaypointMgr() { } -        ~SmartWaypointMgr(); -      public:          static SmartWaypointMgr* instance();          void LoadFromDB(); -        WPPath* GetPath(uint32 id) -        { -            if (waypoint_map.find(id) != waypoint_map.end()) -                return waypoint_map[id]; -            else return nullptr; -        } +        WaypointPath const* GetPath(uint32 id);      private: -        std::unordered_map<uint32, WPPath*> waypoint_map; +        SmartWaypointMgr() { } +        ~SmartWaypointMgr() { } + +        std::unordered_map<uint32, WaypointPath> _waypointStore;  }; +#define sSmartWaypointMgr SmartWaypointMgr::instance() +  // all events for a single entry  typedef std::vector<SmartScriptHolder> SmartAIEventList;  typedef std::vector<SmartScriptHolder> SmartAIEventStoredList; @@ -1627,5 +1606,5 @@ class TC_GAME_API SmartAIMgr  };  #define sSmartScriptMgr SmartAIMgr::instance() -#define sSmartWaypointMgr SmartWaypointMgr::instance() +  #endif | 
