/* * Copyright (C) 2005-2008 MaNGOS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ByteBuffer.h" #include "TargetedMovementGenerator.h" #include "Errors.h" #include "Creature.h" #include "MapManager.h" #include "DestinationHolderImp.h" #define SMALL_ALPHA 0.05f #include /* struct StackCleaner { Creature &i_creature; StackCleaner(Creature &creature) : i_creature(creature) {} void Done(void) { i_creature.StopMoving(); } ~StackCleaner() { i_creature->Clear(); } }; */ template void TargetedMovementGenerator::_setTargetLocation(T &owner) { if( !i_target.isValid() || !&owner ) return; if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED) ) return; // prevent redundant micro-movement for pets, other followers. if(i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset)) return; float x, y, z; if(!i_offset) { // to nearest contact position i_target->GetContactPoint( &owner, x, y, z ); } else { // to at i_offset distance from target and i_angle from target facing i_target->GetClosePoint(x,y,z,owner.GetObjectSize() + i_offset,i_angle); } Traveller traveller(owner); i_destinationHolder.SetDestination(traveller, x, y, z); owner.addUnitState(i_offset ? UNIT_STAT_FOLLOW : UNIT_STAT_CHASE); } template void TargetedMovementGenerator::Initialize(T &owner) { if(!&owner) return; owner.setMoveRunFlag(true); _setTargetLocation(owner); } template void TargetedMovementGenerator::Finalize(T &owner) { owner.clearUnitState(i_offset ? UNIT_STAT_FOLLOW : UNIT_STAT_CHASE); } template void TargetedMovementGenerator::Reset(T &owner) { Initialize(owner); } template bool TargetedMovementGenerator::Update(T &owner, const uint32 & time_diff) { if(!i_target.isValid()) return false; if( !&owner || !owner.isAlive()) return true; if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | 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 false; } // 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 (!owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.getVictim() != i_target.getTarget()) return true; Traveller traveller(owner); if( !i_destinationHolder.HasDestination() ) _setTargetLocation(owner); if( owner.IsStopped() && !i_destinationHolder.HasArrived() ) { owner.addUnitState(i_offset ? UNIT_STAT_FOLLOW : UNIT_STAT_CHASE); i_destinationHolder.StartTravel(traveller); return true; } if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false)) { // put targeted movement generators on a higher priority if (owner.GetObjectSize()) i_destinationHolder.ResetUpdate(50); float deltamax = owner.GetFloatValue(UNIT_FIELD_COMBATREACH)* 0.9 > CONTACT_DISTANCE + 0.01 ? owner.GetFloatValue(UNIT_FIELD_COMBATREACH)* 0.9 : CONTACT_DISTANCE + 0.01; float dist = i_target->GetObjectSize() + owner.GetObjectSize() + deltamax; // try to counter precision differences if( i_destinationHolder.GetDistanceFromDestSq(*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; owner.SetInFront(i_target.getTarget()); if(owner.canReachWithAttack(i_target.getTarget()) && !owner.hasUnitState(UNIT_STAT_FOLLOW)) owner.Attack(i_target.getTarget()); } } return true; } template Unit* TargetedMovementGenerator::GetTarget() const { return i_target.getTarget(); } template void TargetedMovementGenerator::_setTargetLocation(Player &); template void TargetedMovementGenerator::_setTargetLocation(Creature &); template void TargetedMovementGenerator::Initialize(Player &); template void TargetedMovementGenerator::Initialize(Creature &); template void TargetedMovementGenerator::Finalize(Player &); template void TargetedMovementGenerator::Finalize(Creature &); template void TargetedMovementGenerator::Reset(Player &); template void TargetedMovementGenerator::Reset(Creature &); template bool TargetedMovementGenerator::Update(Player &, const uint32 &); template bool TargetedMovementGenerator::Update(Creature &, const uint32 &); template Unit* TargetedMovementGenerator::GetTarget() const; template Unit* TargetedMovementGenerator::GetTarget() const;