void PointMovementGenerator<T>:: Finalize(T &unit) { unit.ClearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); if (unit.movespline->Finalized()) MovementInform(unit); }
void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner) { if (!owner) return; if (!i_path || i_path->empty()) return; if (m_isArrivalDone) return; owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); m_isArrivalDone = true; if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance) { sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for " UI64FMTD ".", i_path->at(i_currentNode)->event_id, i_currentNode, owner->GetGUID()); owner->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, owner, NULL); } // Inform script MovementInform(owner); owner->UpdateWaypointID(i_currentNode); Stop(i_path->at(i_currentNode)->delay); }
void PointMovementGenerator<T>:: Finalize(T &unit) { if (unit.hasUnitState(UNIT_STAT_CHARGING)) unit.clearUnitState(UNIT_STAT_CHARGING | UNIT_STAT_JUMPING); if (arrived) // without this crash! MovementInform(unit); }
void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature) { if (!i_path || i_path->nodes.empty()) return; WaypointNode const &waypoint = i_path->nodes.at(i_currentNode); if (waypoint.delay) { creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); Stop(waypoint.delay); } if (waypoint.eventId && urand(0, 99) < waypoint.eventChance) { TC_LOG_DEBUG("maps.script", "Creature movement start script %u at point %u for %s.", waypoint.eventId, i_currentNode, creature->GetGUID().ToString().c_str()); creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); creature->GetMap()->ScriptsStart(sWaypointScripts, waypoint.eventId, creature, nullptr); } // Inform script MovementInform(creature); creature->UpdateWaypointID(i_currentNode); creature->SetWalk(waypoint.moveType != WAYPOINT_MOVE_TYPE_RUN); }
void EffectMovementGenerator::Finalize(Unit* owner) { if (!owner) return; MovementInform(owner); }
bool PointMovementGenerator<T>::Update(T &unit, const uint32 &diff) { if(!&unit) return false; if(unit.hasUnitState(UNIT_STAT_CAN_NOT_MOVE & ~UNIT_STAT_ON_VEHICLE)) { unit.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } unit.addUnitState(UNIT_STAT_ROAMING_MOVE); Traveller<T> traveller(unit); i_destinationHolder.UpdateTraveller(traveller, diff, false); if(i_destinationHolder.HasArrived()) { unit.StopMoving(); MovementInform(unit); return false; } return true; }
void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature) { if (!i_path || i_path->empty()) return; if (m_isArrivalDone) return; m_isArrivalDone = true; if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance) { TC_LOG_DEBUG("maps.script", "Creature movement start script %u at point %u for " UI64FMTD ".", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID()); creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL); } // Inform script MovementInform(creature); creature->UpdateWaypointID(i_currentNode); if (i_path->at(i_currentNode)->delay) { creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); Stop(i_path->at(i_currentNode)->delay); } }
void PointMovementGenerator<T>::Finalize(T& unit) { unit.clearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_ROAMING_MOVE); if (i_destinationHolder.HasArrived()) MovementInform(unit); }
void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature) { if (!i_path || i_path->empty()) return; if (m_isArrivalDone) return; creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); m_isArrivalDone = true; if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for " UI64FMTD ".", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID()); #endif creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL); } // Inform script MovementInform(creature); creature->UpdateWaypointID(i_currentNode); if (i_path->at(i_currentNode)->delay) { creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); Stop(i_path->at(i_currentNode)->delay); } }
bool PointMovementGenerator<T>::Update(T &unit, const uint32 &diff) { if(!&unit) return false; if(unit.hasUnitState(UNIT_STAT_CAN_NOT_MOVE)) { unit.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } unit.addUnitState(UNIT_STAT_ROAMING_MOVE); Traveller<T> traveller(unit); if (i_destinationHolder.UpdateTraveller(traveller, diff, false)) { if (!IsActive(unit)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } if(i_destinationHolder.HasArrived()) { unit.clearUnitState(UNIT_STAT_ROAMING_MOVE); MovementInform(unit); return false; } return true; }
void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature) { if (!i_path || i_path->empty()) return; m_lastReachedWaypoint = i_currentNode; if (m_isArrivalDone) return; creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); m_isArrivalDone = true; WaypointPath::const_iterator currPoint = i_path->find(i_currentNode); BLIZZLIKE_ASSERT(currPoint != i_path->end()); WaypointNode const& node = currPoint->second; if (node.script_id) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for %s.", node.script_id, i_currentNode, creature.GetGuidStr().c_str()); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, node.script_id, &creature, &creature); } // We have reached the destination and can process behavior if (WaypointBehavior* behavior = node.behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) creature.CastSpell(&creature, behavior->spell, false); if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for (; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } creature.MonsterSay(behavior->textid[rand() % i], LANG_UNIVERSAL); } else creature.MonsterSay(behavior->textid[0], LANG_UNIVERSAL); } } // Inform script MovementInform(creature); Stop(node.delay); }
void PointMovementGenerator<T>::DoFinalize(T* unit) { if (unit->HasUnitState(UNIT_STATE_CHARGING)) unit->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); if (unit->movespline->Finalized()) MovementInform(unit); }
void PointMovementGenerator<T>:: Finalize(T& unit) { if (unit.HasUnitState(UNIT_STATE_CHARGING)) unit.ClearUnitState(UNIT_STATE_CHARGING | UNIT_STATE_JUMPING); if (unit.movespline->Finalized()) MovementInform(unit); }
void PointMovementGenerator<T>::DoFinalize(T* owner, bool active, bool movementInform) { MovementGenerator::AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); if (active) owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); if (movementInform && MovementGenerator::HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) MovementInform(owner); }
void PointMovementGenerator<T>::Finalize(T& unit) { unit.clearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_ROAMING_MOVE); if (unit.GetTypeId() == TYPEID_UNIT) unit.UpdateSpeed(MOVE_RUN, true); if (unit.movespline->Finalized()) MovementInform(unit); }
void PointMovementGenerator<T>::DoFinalize(T* owner) { if (!owner) return; owner->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); if (owner->movespline->Finalized()) MovementInform(owner); }
void Reset() { nextMovementTimer = 0; actualAngle = me->GetAngle(CenterPos.GetPositionX(), CenterPos.GetPositionY()); direction = urand(0, 1); if (direction) myPositionZ = 435.0f; else myPositionZ = 440.0f; // Enable Movements MovementInform(POINT_MOTION_TYPE, POINT_KRIKTHIK_CIRCLE); me->setActive(true); }
void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature) { if (!i_path || i_path->empty()) return; if (m_isArrivalDone) return; creature.ClearUnitState(UNIT_STAT_ROAMING_MOVE); m_isArrivalDone = true; if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance) { sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for %u.", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID()); creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL/*, false*/); } // Inform script MovementInform(creature); Stop(i_path->at(i_currentNode)->delay); }
bool PointMovementGenerator<T>::Update(T &unit, const uint32 &diff) { if(!&unit) return false; if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED)) return true; Traveller<T> traveller(unit); i_destinationHolder.UpdateTraveller(traveller, diff, false); if(i_destinationHolder.HasArrived()) { unit.StopMoving(); MovementInform(unit); return false; } return true; }
bool TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (!&owner || !owner.isAlive()) return true; if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED)) return true; // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true) || owner.hasUnitState(UNIT_STAT_CASTING)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } if (!owner.HasAuraType(SPELL_AURA_MOD_INVISIBILITY) && !owner.canSeeOrDetect(i_target.getTarget(), true)) { owner.AttackStop(); if (owner.GetOwner()) owner.GetMotionMaster()->MoveFollow(owner.GetOwner(), PET_FOLLOW_DIST, owner.GetFollowAngle()); else owner.StopMoving(); return true; } // prevent crash after creature killed pet if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget()) return true; if (m_usePathfinding) { if (i_path && (i_path->getPathType() & PATHFIND_NOPATH)) return true; Traveller<T> traveller(owner); if (!i_destinationHolder.HasDestination()) _setTargetLocation(owner); if (i_destinationHolder.UpdateTraveller(traveller, time_diff, i_recalculateTravel || owner.IsStopped())) { // put targeted movement generators on a higher priority if (owner.GetCombatReach()) i_destinationHolder.ResetUpdate(100); float x,y,z; i_target->GetPosition(x, y, z); PathNode next_point(x, y, z); bool targetMoved = false, needNewDest = false; bool forceRecalc = i_recalculateTravel || owner.IsStopped(); if (i_path && !forceRecalc) { PathNode end_point = i_path->getEndPosition(); next_point = i_path->getNextPosition(); //More distance let have better performance, less distance let have more sensitive reaction at target move. float dist = owner.GetCombatReach() + sWorld.getRate(RATE_TARGET_POS_RECALCULATION_RANGE); needNewDest = i_destinationHolder.HasArrived() && (!i_path->inRange(next_point, i_path->getActualEndPosition(), dist, dist) || !owner.IsWithinLOSInMap(i_target.getTarget())); if(!needNewDest) { // GetClosePoint() will always return a point on the ground, so we need to // handle the difference in elevation when the creature is flying if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly()) targetMoved = i_target->GetDistanceSqr(end_point.x, end_point.y, end_point.z) > dist*dist; else targetMoved = i_target->GetDistance2d(end_point.x, end_point.y) > dist; } } // target moved if (!i_path || targetMoved || needNewDest || forceRecalc) { // (re)calculate path _setTargetLocation(owner); next_point = i_path->getNextPosition(); // Set new Angle For Map:: owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); } // Update the Angle of the target only for Map::, no need to send packet for player else if (!i_angle && !owner.HasInArc(0.01f, next_point.x, next_point.y)) owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel) { i_recalculateTravel = false; //Angle update will take place into owner.StopMoving() owner.SetInFront(i_target.getTarget()); owner.StopMoving(); if(owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(i_target.getTarget(), true); } } } else { Traveller<T> traveller(owner); if (!i_destinationHolder.HasDestination()) { _setTargetLocation(owner); } else if (owner.IsStopped() && !i_destinationHolder.HasArrived()) { owner.addUnitState(UNIT_STAT_CHASE); i_destinationHolder.StartTravel(traveller); return true; } if (i_destinationHolder.UpdateTraveller(traveller, time_diff)) { // target moved if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY() || i_targetZ != i_target->GetPositionZ()) { if(_setTargetLocation(owner) || !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.SetInFront(i_target.getTarget()); i_target->GetPosition(i_targetX, i_targetY, i_targetZ); } if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel) { i_recalculateTravel = false; //Angle update will take place into owner.StopMoving() owner.SetInFront(i_target.getTarget()); owner.StopMoving(); if(owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(i_target.getTarget(),true); } } } // Implemented for PetAI to handle resetting flags when pet owner reached if (i_destinationHolder.HasArrived()) MovementInform(owner); return true; }
bool WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff) { if (!&unit) return true; if (!path_id) return false; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) return true; // Clear the generator if the path doesn't exist if (!waypoints || !waypoints->size()) return false; Traveller<Creature> traveller(unit); i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, true); if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP) { if (unit.IsStopped()) { if (StopedByPlayer) { ASSERT(node); InitTraveller(unit, *node); i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); StopedByPlayer = false; return true; } if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint { if (repeating) // If the movement is repeating i_currentNode = 0; // Start moving all over again else { unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation()); unit.GetMotionMaster()->Initialize(); return false; // Clear the waypoint movement } } else ++i_currentNode; node = waypoints->at(i_currentNode); InitTraveller(unit, *node); i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); //Call for creature group update if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit) unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); } else { //Determine waittime if (node->delay) i_nextMoveTime.Reset(node->delay); //note: disable "start" for mtmap if (node->event_id && urand(0,99) < node->event_chance) unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/); i_destinationHolder.ResetTravelTime(); MovementInform(unit); unit.UpdateWaypointID(i_currentNode); unit.ClearUnitState(UNIT_STAT_ROAMING); unit.Relocate(node->x, node->y, node->z); } } else { if (unit.IsStopped() && !i_destinationHolder.HasArrived()) { if (!StopedByPlayer) { i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); StopedByPlayer = true; } } } return true; }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (creature.hasUnitState(UNIT_STAT_NOT_MOVE)) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } if (i_currentNode >= i_path->size()) { sLog.outError("WaypointMovement currentNode (%u) is equal or bigger than path size (creature entry %u)", i_currentNode, creature.GetEntry()); i_currentNode = 0; } CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { // Timer has elapsed, meaning this part controlled it if (i_nextMoveTime.Passed()) { SetStoppedByPlayer(false); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // Now we re-set destination to same node and start travel const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else // if( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStoppedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStoppedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if (creature.IsStopped()) { if (!m_isArrivalDone) { if (i_path->at(i_currentNode).orientation != 100) creature.SetOrientation(i_path->at(i_currentNode).orientation); if (i_path->at(i_currentNode).script_id) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for creature %u (entry %u).", i_path->at(i_currentNode).script_id, i_currentNode, creature.GetDBTableGUIDLow(), creature.GetEntry()); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, i_path->at(i_currentNode).script_id, &creature, &creature); } // We have reached the destination and can process behavior if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) { creature.CastSpell(&creature, behavior->spell, false); if (!IsActive(creature)) // force stop processing (cast can change movegens list) return true; // not expire now, but already lost } if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for(; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } } // wpBehaviour found // Can only do this once for the node m_isArrivalDone = true; // Inform script MovementInform(creature); if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // prevent a crash at empty waypoint path. if (!i_path || i_path->empty() || i_currentNode >= i_path->size()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } } } // i_creature.IsStopped() // This is at the end of waypoint segment (incl. was previously stopped by player, extending the time) if (i_nextMoveTime.Passed()) { // If stopped then begin a new move segment if (creature.IsStopped()) { creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior) { if (behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } // behavior for "departure" of the current node is done m_isArrivalDone = false; // Proceed with increment current node and then send to the next destination ++i_currentNode; // Oops, end of the line so need to start from the beginning if (i_currentNode >= i_path->size()) i_currentNode = 0; if (i_path->at(i_currentNode).orientation != 100) creature.SetOrientation(i_path->at(i_currentNode).orientation); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else { // If not stopped then stop it creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); SetStoppedByPlayer(false); // Set TimeTracker to waittime for the current node i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); } } return true; }
void GenericMovementGenerator::Finalize(Unit* owner) { MovementInform(owner); }
void PointMovementGenerator<T>::Finalize(T &unit) { unit.clearUnitState(UNIT_STAT_ROAMING | UNIT_STAT_ROAMING_MOVE); MovementInform(unit); }
void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature) { if (!i_path || i_path->empty()) return; m_lastReachedWaypoint = i_currentNode; if (m_isArrivalDone) return; creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); m_isArrivalDone = true; WaypointPath::const_iterator currPoint = i_path->find(i_currentNode); MANGOS_ASSERT(currPoint != i_path->end()); WaypointNode const& node = currPoint->second; if (node.script_id) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for %s.", node.script_id, i_currentNode, creature.GetGuidStr().c_str()); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, node.script_id, &creature, &creature); } // We have reached the destination and can process behavior if (WaypointBehavior* behavior = node.behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) creature.CastSpell(&creature, behavior->spell, false); if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { int32 textId = behavior->textid[0]; // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for (; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } textId = behavior->textid[urand(0, i - 1)]; } if (MangosStringLocale const* textData = sObjectMgr.GetMangosStringLocale(textId)) creature.MonsterText(textData, NULL); else sLog.outErrorDb("%s reached waypoint %u, attempted to do text %i, but required text-data could not be found", creature.GetGuidStr().c_str(), i_currentNode, textId); } } // Inform script MovementInform(creature); Stop(node.delay); }
bool TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (!&owner || !owner.isAlive()) return true; if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED)) return true; // prevent movement while casting spells with cast time or channel time if (owner.hasUnitState(UNIT_STAT_CASTING)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } // prevent crash after creature killed pet if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget()) return true; Traveller<T> traveller(owner); if (!i_destinationHolder.HasDestination()) _setTargetLocation(owner); else if (owner.IsStopped() && !i_destinationHolder.HasArrived()) { owner.addUnitState(UNIT_STAT_CHASE); i_destinationHolder.StartTravel(traveller); return true; } if (i_destinationHolder.UpdateTraveller(traveller, time_diff)) { // put targeted movement generators on a higher priority //if (owner.GetObjectSize()) //i_destinationHolder.ResetUpdate(50); // target moved if (i_targetX != i_target->GetPositionX() || i_targetY != i_target->GetPositionY() || i_targetZ != i_target->GetPositionZ()) { if (_setTargetLocation(owner) || !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.SetInFront(i_target.getTarget()); i_target->GetPosition(i_targetX, i_targetY, i_targetZ); } if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel) { i_recalculateTravel = false; //Angle update will take place into owner.StopMoving() owner.SetInFront(i_target.getTarget()); owner.StopMoving(); if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(i_target.getTarget(),true); } } // Implemented for PetAI to handle resetting flags when pet owner reached if (i_destinationHolder.HasArrived()) MovementInform(owner); return true; }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if(!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) return true; // prevent a crash at empty waypoint path. if(!i_path || i_path->empty()) return true; // i_path was modified by chat commands for example if(i_path->size() != i_hasDone.size()) i_hasDone.resize(i_path->size()); if(i_currentNode >= i_path->size()) i_currentNode = 0; CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, false, true); // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it { SetStopedByPlayer(false); // Now we re-set destination to same node and start travel creature.addUnitState(UNIT_STAT_ROAMING); if (creature.canFly()) creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else // if( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStopedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStopedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if( creature.IsStopped()) { uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (!i_hasDone[idx]) { if (i_path->at(idx).orientation !=100) creature.SetOrientation(i_path->at(idx).orientation); if(WaypointBehavior *behavior = i_path->at(idx).behavior) { if(behavior->emote != 0) creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote); if(behavior->spell != 0) creature.CastSpell(&creature,behavior->spell, false); if(behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if(behavior->textid[0]) { // Not only one text is set if( behavior->textid[1] ) { // Select one from max 5 texts (0 and 1 laready checked) int i = 2; for( ; i < MAX_WAYPOINT_TEXT; ++i ) if( !behavior->textid[i] ) break; creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } i_hasDone[idx] = true; MovementInform(creature); } // wpBehaviour found } // HasDone == false } // i_creature.IsStopped() if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player { if( creature.IsStopped() ) // If stopped then begin a new move segment { creature.addUnitState(UNIT_STAT_ROAMING); if (creature.canFly()) creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (i_path->at(idx).orientation !=100) creature.SetOrientation(i_path->at(idx).orientation); if(WaypointBehavior *behavior = i_path->at(idx).behavior ) { i_hasDone[idx] = false; if(behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } } else // If not stopped then stop it and set the reset of TimeTracker to waittime { creature.StopMoving(); SetStopedByPlayer(false); i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); ++i_currentNode; if( i_currentNode >= i_path->size() ) i_currentNode = 0; } } return true; }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (creature.hasUnitState(UNIT_STAT_NOT_MOVE)) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } if (i_currentNode >= i_path->size()) i_currentNode = 0; CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { // Timer has elapsed, meaning this part controlled it if (i_nextMoveTime.Passed()) { SetStoppedByPlayer(false); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // Now we re-set destination to same node and start travel const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else // if( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStoppedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStoppedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if (creature.IsStopped() && !i_hasDone) // creature is waiting on a waypoint and hasn't done the behavior yet { uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (i_path->at(idx).orientation != 100) creature.SetOrientation(i_path->at(idx).orientation); if (WaypointBehavior *behavior = i_path->at(idx).behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) { creature.CastSpell(&creature, behavior->spell, false); if (!IsActive(creature)) // force stop processing (cast can change movegens list) return true; // not expire now, but already lost } if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for(; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } } // behavior done i_hasDone = true; MovementInform(creature); if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // prevent a crash at empty waypoint path. if (!i_path || i_path->empty() || i_currentNode >= i_path->size()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } } // i_creature.IsStopped() // This is at the end of waypoint segment or has been stopped by player if (i_nextMoveTime.Passed()) { // If stopped then begin a new move segment if (creature.IsStopped()) { creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (i_path->at(idx).orientation != 100) creature.SetOrientation(i_path->at(idx).orientation); if (WaypointBehavior *behavior = i_path->at(idx).behavior) { if (behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } } else { // If not stopped then stop it and set the reset of TimeTracker to waittime creature.StopMoving(); SetStoppedByPlayer(false); i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); ++i_currentNode; i_hasDone = false; if (i_currentNode >= i_path->size()) i_currentNode = 0; } } return true; }
bool TargetedMovementGeneratorMedium<T, D>::Update(T& owner, const uint32& time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (!owner.IsAlive()) return true; if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING | UNIT_STATE_DISTRACTED)) return true; // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCast(false, false, true) || owner.HasUnitState(UNIT_STATE_CASTING)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } if (!owner.HasAuraType(SPELL_AURA_MOD_INVISIBILITY) && !owner.CanSeeOrDetect(i_target.getTarget(), true)) { owner.AttackStop(); if (owner.GetOwner()) owner.GetMotionMaster()->MoveFollow(owner.GetOwner(), PET_FOLLOW_DIST, owner.GetFollowAngle()); else owner.StopMoving(); return true; } // prevent crash after creature killed pet if (!owner.HasUnitState(UNIT_STATE_FOLLOW) && owner.GetVictim() != i_target.getTarget()) return true; if (i_path && i_path->getPathType() & PATHFIND_NOPATH) { if (Creature* me = owner.ToCreature()) { if (m_evadeTimer <= time_diff) { if (me->AI()) me->AI()->EnterEvadeMode(); } else m_evadeTimer -= time_diff; } return true; } bool targetMoved = false; i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { i_recheckDistance.Reset(this->GetMovementGeneratorType() == FOLLOW_MOTION_TYPE ? 50 : 100); G3D::Vector3 dest = owner.movespline->FinalDestination(); targetMoved = RequiresNewPosition(owner, dest.x, dest.y, dest.z); } if (m_speedChanged || targetMoved) _setTargetLocation(owner, targetMoved); if (owner.movespline->Finalized()) { if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget())) owner.SetInFront(i_target.getTarget()); if (!i_targetReached) { i_targetReached = true; static_cast<D*>(this)->_reachTarget(owner); } } // Implemented for PetAI to handle resetting flags when pet owner reached if (owner.movespline->Finalized()) MovementInform(owner); return true; }
bool TargetedMovementGenerator<T>::Update(T &owner, const uint32 & time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (!&owner || !owner.isAlive()) return true; if (owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DISTRACTED)) return true; // prevent movement while casting spells with cast time or channel time if (owner.hasUnitState(UNIT_STAT_CASTING)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } // prevent crash after creature killed pet if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget()) return true; if (i_path && (i_path->getPathType() & PATHFIND_NOPATH)) return true; Traveller<T> traveller(owner); if (!i_destinationHolder.HasDestination()) _setTargetLocation(owner); if (i_destinationHolder.UpdateTraveller(traveller, time_diff, i_recalculateTravel || owner.IsStopped())) { // put targeted movement generators on a higher priority if (owner.GetObjectSize()) i_destinationHolder.ResetUpdate(100); float dist = owner.GetCombatReach() + sWorld.getRate(RATE_TARGET_POS_RECALCULATION_RANGE); float x,y,z; i_target->GetPosition(x, y, z); PathNode next_point(x, y, z); bool targetMoved = false, needNewDest = false; if (i_path) { PathNode end_point = i_path->getEndPosition(); next_point = i_path->getNextPosition(); needNewDest = i_destinationHolder.HasArrived() && !inRange(next_point, i_path->getActualEndPosition(), dist, dist); // GetClosePoint() will always return a point on the ground, so we need to // handle the difference in elevation when the creature is flying if (owner.GetTypeId() == TYPEID_UNIT && owner.ToCreature()->canFly()) targetMoved = i_target->GetDistanceSqr(end_point.x, end_point.y, end_point.z) >= dist * dist; else targetMoved = i_target->GetDistance2d(end_point.x, end_point.y) >= dist; } // target moved if (!i_path || targetMoved || needNewDest || i_recalculateTravel || owner.IsStopped()) { // (re)calculate path _setTargetLocation(owner); next_point = i_path->getNextPosition(); // Set new Angle For Map:: owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); } // Update the Angle of the target only for Map::, no need to send packet for player else if (!i_angle && !owner.HasInArc(0.01f, next_point.x, next_point.y)) owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel) { i_recalculateTravel = false; //Angle update will take place into owner.StopMoving() owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y)); owner.StopMoving(); if (owner.IsWithinMeleeRange(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(i_target.getTarget(), true); } } // Implemented for PetAI to handle resetting flags when pet owner reached if (i_destinationHolder.HasArrived()) MovementInform(owner); return true; }