void FollowMovementGenerator<Player>::Initialize(Player& owner) { owner.addUnitState(UNIT_STAT_FOLLOW | UNIT_STAT_FOLLOW_MOVE); _updateSpeed(owner); _setTargetLocation(owner, 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; }
void ChaseMovementGenerator<Creature>::Initialize(Creature& owner) { owner.SetWalk(false, false); // Chase movement is running owner.addUnitState(UNIT_STAT_CHASE | UNIT_STAT_CHASE_MOVE); _setTargetLocation(owner, true); }
void ChaseMovementGenerator<Creature>::Initialize(Creature& owner) { owner.SetWalk(false, false); // Chase movement is running owner.addUnitState(UNIT_STAT_CHASE); // _MOVE set in _SetTargetLocation after required checks _setTargetLocation(owner, 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_STAT_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && owner.hasUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); return true; } bool targetMoved = false; i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { i_recheckDistance.Reset(100); // More distance let have better performance, less distance let have more sensitive reaction at target move. float allowed_dist = owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE); G3D::Vector3 dest = owner.movespline->FinalDestination(); if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly()) targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist); else targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist); // If we have a following angle, the followed object isn't targeting us and its orientation changed a lot -- @Rikub if (!targetMoved && i_angle && i_target->GetTargetGuid() != owner.GetObjectGuid() && fabs(i_target->GetOrientation() - i_targetAngle) > M_PI_F / 3) // => 120° arc { i_targetAngle = i_target->GetOrientation(); targetMoved = true; } } if (m_speedChanged || targetMoved) _setTargetLocation(owner, targetMoved); if (owner.movespline->Finalized()) { if (!owner.HasInArc(0.01f, i_target.getTarget())) owner.SetInFront(i_target.getTarget()); if (!i_targetReached) { i_targetReached = true; static_cast<D*>(this)->_reachTarget(owner); } } return true; }
void ChaseMovementGenerator<Player>::Initialize(Player &owner) { owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE); _setTargetLocation(owner); }
void FollowMovementGenerator<Creature>::Initialize(Creature &owner) { owner.AddUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE); _updateSpeed(owner); _setTargetLocation(owner); }
void HomeMovementGenerator<Creature>::Initialize(Creature & owner) { owner.RemoveSplineFlag(SPLINEFLAG_WALKMODE); _setTargetLocation(owner); }
void HomeMovementGenerator<Creature>::Initialize(Creature & owner) { owner.RemoveMonsterMoveFlag(MONSTER_MOVE_WALK); _setTargetLocation(owner); }
bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T* owner, uint32 time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (!owner || !owner->IsAlive()) return false; if (owner->HasUnitState(UNIT_STATE_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner->HasUnitState(UNIT_STATE_CASTING)) { if (!owner->IsStopped()) owner->StopMoving(); return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); return true; } bool targetMoved = false; i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { i_recheckDistance.Reset(100); //More distance let have better performance, less distance let have more sensitive reaction at target move. float allowed_dist = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE); G3D::Vector3 dest = owner->movespline->FinalDestination(); if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->CanFly()) targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist); else targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist); } if (evadeTimer) { if (evadeTimer <= time_diff) { if ((failedCounter >= 30) && (owner->GetTypeId() == TYPEID_UNIT) && owner->IsAIEnabled) owner->ToCreature()->AI()->EnterEvadeMode(); failedCounter = 0; evadeTimer = 0; } else evadeTimer -= time_diff; } if (i_recalculateTravel || targetMoved) _setTargetLocation(owner, targetMoved); if (owner->movespline->Finalized()) { static_cast<D*>(this)->MovementInform(owner); 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); } } 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; }
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; // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true, true)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } if (owner.hasUnitState(UNIT_STAT_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && owner.hasUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); 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(i_target.getTarget(), 0.01f)) owner.SetInFront(i_target.getTarget()); if (!i_targetReached) { i_targetReached = true; static_cast<D*>(this)->_reachTarget(owner); } } return true; }
bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (!owner || !owner->isAlive()) return false; if (owner->HasUnitState(UNIT_STATE_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner->HasUnitState(UNIT_STATE_CASTING)) { if (!owner->IsStopped()) owner->StopMoving(); return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); return true; } // Check whether pet got send to cast a spell if (i_spell) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i_spell); Spell* spell = new Spell(owner->ToUnit(), spellInfo, TRIGGERED_NONE); SpellCastResult result = spell->CheckPetCast(i_target.getTarget()); if (result == SPELL_CAST_OK) { spell->prepare(&(spell->m_targets)); // Reset i_spell here to prevent chaincasting. i_spell = 0; } else { spell->finish(false); delete spell; } } bool targetMoved = false; i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { i_recheckDistance.Reset(100); //More distance let have better performance, less distance let have more sensitive reaction at target move. float allowed_dist = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE); G3D::Vector3 dest = owner->movespline->FinalDestination(); targetMoved = !(i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist) && i_target->IsWithinLOS(dest.x, dest.y, dest.z)); } if (i_recalculateTravel || targetMoved) _setTargetLocation(owner, targetMoved); if (owner->movespline->Finalized()) { static_cast<D*>(this)->MovementInform(owner); 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); } } 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_STAT_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); return true; } i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { i_recheckDistance.Reset(100); //More distance let have better performance, less distance let have more sensitive reaction at target move. float allowed_dist = owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE); G3D::Vector3 dest = owner.movespline->FinalDestination(); bool targetMoved = false; if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly()) targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist); else targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist); if (targetMoved) _setTargetLocation(owner); } 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); } } else { if (i_recalculateTravel) _setTargetLocation(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; 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 TargetedMovementGenerator::Update(Creature &owner, const uint32 & time_diff) { if( !&owner || !owner.isAlive() || !&i_target ) return true; if( owner.hasUnitState(UNIT_STAT_ROOT) || owner.hasUnitState(UNIT_STAT_STUNDED) || owner.hasUnitState(UNIT_STAT_FLEEING)) return true; if( !owner.isInCombat() && !owner.hasUnitState(UNIT_STAT_FOLLOW) ) { //owner.AIM_Initialize(); This case must be the one, when a creature aggroed you. By Initalized a new AI, we prevented to Ai::_stopAttack() to be executed properly. return true; } // prevent crash after creature killed pet if (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != &i_target) return true; Traveller<Creature> traveller(owner); if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false)) { // put targeted movement generators on a higher priority if (owner.GetObjectSize()) i_destinationHolder.ResetUpdate(50); float dist = i_target.GetObjectSize() + owner.GetObjectSize() + OBJECT_CONTACT_DISTANCE; // try to counter precision differences if( i_destinationHolder.GetDistanceFromDestSq(i_target) > dist * dist + 0.1) _setTargetLocation(owner, 0); else if ( !owner.HasInArc( 0.1f, &i_target ) ) { owner.SetInFront(&i_target); if( i_target.GetTypeId() == TYPEID_PLAYER ) owner.SendUpdateToPlayer( (Player*)&i_target ); } if( !owner.IsStopped() && i_destinationHolder.HasArrived()) { owner.StopMoving(); if(owner.canReachWithAttack(&i_target) && !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(&i_target); } } /* //SpellEntry* spellInfo; if( reach ) { if( owner.GetDistance2dSq( &i_target ) > 0.0f ) { DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target )); owner.addUnitState(UNIT_STAT_CHASE); _setTargetLocation(owner, 0); } else if ( !owner.HasInArc( 0.0f, &i_target ) ) { DEBUG_LOG("MOVEMENT : Orientation = %f",owner.GetAngle(&i_target)); owner.SetInFront(&i_target); if( i_target.GetTypeId() == TYPEID_PLAYER ) owner.SendUpdateToPlayer( (Player*)&i_target ); } if( !owner.isInCombat() ) { owner.AIM_Initialize(); return; } } else if( i_target.isAlive() ) { if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() ) { if( spellInfo = owner.reachWithSpellAttack( &i_target ) ) { _spellAtack(owner, spellInfo); return; } } if( owner.GetDistance2dSq( &i_target ) > 0.0f ) { DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target )); owner.addUnitState(UNIT_STAT_CHASE); _setTargetLocation(owner, 0); } } else if( !i_targetedHome ) { if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() && (spellInfo = owner.reachWithSpellAttack(&i_target)) ) { _spellAtack(owner, spellInfo); return; } _setTargetLocation(owner, 0); if(reach) { if( reach && owner.canReachWithAttack(&i_target) ) { owner.StopMoving(); if(!owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(&i_target); owner.clearUnitState(UNIT_STAT_CHASE); DEBUG_LOG("UNIT IS THERE"); } else { _setTargetLocation(owner, 0); DEBUG_LOG("Continue to chase"); } } }*/ return true; }
void HomeMovementGenerator<Creature>::Initialize(Creature & owner) { _setTargetLocation(owner); }
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; }
void ChaseMovementGenerator<Creature>::Initialize(Creature &owner) { owner.SetWalk(false); owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE); _setTargetLocation(owner); }
bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (!owner || !owner->IsAlive()) return false; if (owner->HasUnitState(UNIT_STATE_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner->HasUnitState(UNIT_STATE_CASTING)) { bool stop = true; if (Spell* spell = owner->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) if (!(spell->GetSpellInfo()->ChannelInterruptFlags & (AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING)) && !(spell->GetSpellInfo()->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) stop = false; if (stop) { // Xinef: delay distance recheck in case of succeeding casts i_recheckDistance.Reset(300); if (!owner->IsStopped()) owner->StopMoving(); return true; } } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); return true; } i_recheckDistanceForced.Update(time_diff); if (i_recheckDistanceForced.Passed()) { i_recheckDistanceForced.Reset(2500); lastOwnerXYZ.Relocate(-5000.0f, -5000.0f, -5000.0f); } i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { i_recheckDistance.Reset(50); //More distance let have better performance, less distance let have more sensitive reaction at target move. float allowed_dist_sq = i_target->GetObjectSize() + owner->GetObjectSize() + MELEE_RANGE - 0.5f; // xinef: if offset is negative (follow distance is smaller than just object sizes), reduce minimum allowed distance which is based purely on object sizes if (i_offset < 0.0f) { allowed_dist_sq += i_offset; allowed_dist_sq = std::max<float>(0.0f, allowed_dist_sq); } allowed_dist_sq *= allowed_dist_sq; G3D::Vector3 dest = owner->movespline->FinalDestination(); if (owner->movespline->onTransport) if (TransportBase* transport = owner->GetDirectTransport()) transport->CalculatePassengerPosition(dest.x, dest.y, dest.z); float dist = (dest - G3D::Vector3(i_target->GetPositionX(),i_target->GetPositionY(),i_target->GetPositionZ())).squaredLength(); float targetMoveDistSq = i_target->GetExactDistSq(&lastTargetXYZ); if (dist >= allowed_dist_sq || (!i_offset && targetMoveDistSq >= 1.5f*1.5f)) if (targetMoveDistSq >= 0.1f*0.1f || owner->GetExactDistSq(&lastOwnerXYZ) >= 0.1f*0.1f) _setTargetLocation(owner, false); } if (owner->movespline->Finalized()) { static_cast<D*>(this)->MovementInform(owner); 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); } } else { if (i_recalculateTravel) _setTargetLocation(owner, false); } return true; }
void ChaseMovementGenerator<Player>::Initialize(Player& owner) { owner.addUnitState(UNIT_STAT_CHASE); // _MOVE set in _SetTargetLocation after required checks _setTargetLocation(owner, 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_STAT_NOT_MOVE | UNIT_STAT_ON_VEHICLE)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); return true; } Traveller<T> traveller(owner); if (!i_destinationHolder.HasDestination()) _setTargetLocation(owner); if (owner.IsStopped() && !i_destinationHolder.HasArrived()) { D::_addUnitStateMove(owner); float x,y,z; i_destinationHolder.GetLocationNowNoMicroMovement(x,y,z); if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly() && !(((Creature*)&owner)->canWalk() && ((Creature*)&owner)->IsAtGroundLevel(x,y,z))) ((Creature&)owner).AddSplineFlag(SPLINEFLAG_UNKNOWN7); i_destinationHolder.StartTravel(traveller); return true; } if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false)) { if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // put targeted movement generators on a higher priority if (owner.GetObjectBoundingRadius()) i_destinationHolder.ResetUpdate(50); float dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE); //More distance let have better performance, less distance let have more sensitive reaction at target move. // try to counter precision differences if (i_destinationHolder.GetDistance3dFromDestSq(*i_target.getTarget()) >= dist * dist) { owner.SetInFront(i_target.getTarget()); // Set new Angle For Map:: _setTargetLocation(owner); //Calculate New Dest and Send data To Player } // Update the Angle of the target only for Map::, no need to send packet for player else if (!i_angle && !owner.HasInArc(0.01f, i_target.getTarget())) owner.SetInFront(i_target.getTarget()); 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(); static_cast<D*>(this)->_reachTarget(owner); } } return true; }
void FollowMovementGenerator<Creature>::Initialize(Creature& owner) { owner.addUnitState(UNIT_STAT_FOLLOW); // _MOVE set in _SetTargetLocation after required checks _updateSpeed(owner); _setTargetLocation(owner, true); }
void HomeMovementGenerator<Creature>::Initialize(Creature & owner) { owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); owner.AddUnitState(UNIT_STAT_EVADE); _setTargetLocation(owner); }
void HomeMovementGenerator<Creature>::Initialize(Creature & owner) { owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); _setTargetLocation(owner); }
bool TargetedMovementGeneratorMedium<T, D>::Update(T& owner, const uint32& time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; if (owner.hasUnitState(UNIT_STAT_NOT_MOVE) || (owner.IsInUnitState(UNIT_ACTION_CHASE) && owner.hasUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT))) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true)) { if (!owner.IsStopped()) { // some spells should be able to be cast while moving // maybe some attribute? here, check the entry of creatures useing these spells switch(owner.GetEntry()) { case 36633: // Ice Sphere (Lich King) case 37562: // Volatile Ooze and Gas Cloud (Putricide) case 37697: break; default: owner.StopMoving(); break; } } if (owner.IsStopped()) return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); if (i_targetSearchingTimer >= TARGET_NOT_ACCESSIBLE_MAX_TIMER) return false; else { i_targetSearchingTimer += 5 * time_diff; return true; } } if (!i_target->isInAccessablePlaceFor(&owner)) return true; bool targetMoved = false; i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { i_recheckDistance.Reset(RECHECK_DISTANCE_TIMER); //More distance let have better performance, less distance let have more sensitive reaction at target move. //float allowed_dist = owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE); float allowed_dist = 0.0f; bool targetIsVictim = owner.getVictim() && owner.getVictim()->GetObjectGuid() == i_target->GetObjectGuid(); if (targetIsVictim) allowed_dist = owner.GetMeleeAttackDistance(owner.getVictim()) + owner.GetObjectBoundingRadius(); else allowed_dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE); if (allowed_dist < owner.GetObjectBoundingRadius()) allowed_dist = owner.GetObjectBoundingRadius(); G3D::Vector3 dest = owner.movespline->FinalDestination(); if (owner.GetTypeId() == TYPEID_UNIT && (((Creature*)&owner)->CanFly() || ((Creature*)&owner)->IsLevitating())) targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist); else targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist); if (targetIsVictim && owner.GetTypeId() == TYPEID_UNIT && !((Creature*)&owner)->IsPet()) { if ((!owner.getVictim() || !owner.getVictim()->isAlive()) && owner.movespline->Finalized()) return false; if (!i_offset && owner.movespline->Finalized() && !owner.CanReachWithMeleeAttack(owner.getVictim()) && !i_target->m_movementInfo.HasMovementFlag(MOVEFLAG_PENDINGSTOP)) { if (i_targetSearchingTimer >= TARGET_NOT_ACCESSIBLE_MAX_TIMER) { return false; } else { i_targetSearchingTimer += RECHECK_DISTANCE_TIMER; targetMoved = true; } } else i_targetSearchingTimer = 0; } else i_targetSearchingTimer = 0; } if (m_speedChanged || targetMoved) _setTargetLocation(owner, true); if (m_speedChanged || targetMoved) _setTargetLocation(owner, targetMoved); if (owner.movespline->Finalized()) { if (fabs(i_angle) < M_NULL_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); } } return true; };
void ChaseMovementGenerator<Player>::Initialize(Player& owner) { owner.AddUnitState(UNIT_STATE_CHASE); // _MOVE set in _SetTargetLocation after required checks _setTargetLocation(owner, true); m_evadeTimer = urand(4000, 8000); }
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_STAT_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time if (owner.IsNonMeleeSpellCasted(false, false, true)) { if (!owner.IsStopped()) owner.StopMoving(); return true; } // prevent crash after creature killed pet if (static_cast<D*>(this)->_lostTarget(owner)) { D::_clearUnitStateMove(owner); 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())) { if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // put targeted movement generators on a higher priority if (owner.GetObjectBoundingRadius()) i_destinationHolder.ResetUpdate(100); //More distance let have better performance, less distance let have more sensitive reaction at target move. float dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + sWorld.getConfig(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, 2*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 && ((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; } 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(); static_cast<D*>(this)->_reachTarget(owner); } } return true; }