2 * Copyright (C) 2005,2006 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "ByteBuffer.h"
20 #include "TargetedMovementGenerator.h"
23 #include "MapManager.h"
25 #include "DestinationHolderImp.h"
27 #define SMALL_ALPHA 0.05
34 StackCleaner(Creature
&creature
) : i_creature(creature
) {}
35 void Done(void) { i_creature
.StopMoving(); }
43 TargetedMovementGenerator::_setTargetLocation(Creature
&owner
, float offset
)
45 if( !&i_target
|| !&owner
)
48 if( owner
.hasUnitState(UNIT_STAT_ROOT
) || owner
.hasUnitState(UNIT_STAT_STUNDED
) )
52 i_target
.GetContactPoint( &owner
, x
, y
, z
);
53 Traveller
<Creature
> traveller(owner
);
54 i_destinationHolder
.SetDestination(traveller
, x
, y
, z
, offset
);
55 owner
.addUnitState(UNIT_STAT_CHASE
);
59 TargetedMovementGenerator::_setAttackRadius(Creature
&owner
)
63 float combat_reach
= owner
.GetFloatValue(UNIT_FIELD_COMBATREACH
);
64 if( combat_reach
<= 0.0f
)
66 //float bounding_radius = owner.GetFloatValue(UNIT_FIELD_BOUNDINGRADIUS);
67 i_attackRadius
= combat_reach
; // - SMALL_ALPHA);
71 TargetedMovementGenerator::Initialize(Creature
&owner
)
75 owner
.setMoveRunFlag(true);
76 _setAttackRadius(owner
);
77 _setTargetLocation(owner
, 0);
81 TargetedMovementGenerator::Reset(Creature
&owner
)
87 TargetedMovementGenerator::TargetedHome(Creature
&owner
)
91 if(owner
.hasUnitState(UNIT_STAT_FLEEING
))
93 DEBUG_LOG("Target home location %u", owner
.GetGUIDLow());
95 owner
.GetRespawnCoord(x
, y
, z
);
96 Traveller
<Creature
> traveller(owner
);
97 i_destinationHolder
.SetDestination(traveller
, x
, y
, z
);
98 traveller
.Relocation(x
,y
,z
);
99 i_targetedHome
= true;
100 owner
.clearUnitState(UNIT_STAT_ALL_STATE
);
104 TargetedMovementGenerator::Update(Creature
&owner
, const uint32
& time_diff
)
106 if( !&owner
|| !owner
.isAlive() || !&i_target
|| i_targetedHome
)
108 if( owner
.hasUnitState(UNIT_STAT_ROOT
) || owner
.hasUnitState(UNIT_STAT_STUNDED
) || owner
.hasUnitState(UNIT_STAT_FLEEING
))
110 if( !owner
.isInCombat() && !owner
.hasUnitState(UNIT_STAT_FOLLOW
) )
112 owner
.AIM_Initialize();
116 // prevent crash after creature killed pet
117 if (!owner
.hasUnitState(UNIT_STAT_FOLLOW
) && owner
.getVictim() != &i_target
)
120 Traveller
<Creature
> traveller(owner
);
121 if (i_destinationHolder
.UpdateTraveller(traveller
, time_diff
, false))
123 // put targeted movement generators on a higher priority
124 i_destinationHolder
.ResetUpdate(50);
125 float dist
= i_target
.GetObjectSize() + owner
.GetObjectSize() + OBJECT_CONTACT_DISTANCE
;
126 // try to counter precision differences
127 if( i_destinationHolder
.GetDistanceFromDestSq(i_target
) > dist
* dist
+ 0.1)
128 _setTargetLocation(owner
, 0);
129 else if ( !owner
.HasInArc( 0.1f
, &i_target
) )
131 owner
.SetInFront(&i_target
);
132 if( i_target
.GetTypeId() == TYPEID_PLAYER
)
133 owner
.SendUpdateToPlayer( (Player
*)&i_target
);
135 if( !owner
.IsStopped() && i_destinationHolder
.HasArrived())
138 if(owner
.canReachWithAttack(&i_target
) && !owner
.hasUnitState(UNIT_STAT_FOLLOW
))
139 owner
.Attack(&i_target
);
144 //SpellEntry* spellInfo;
147 if( owner.GetDistance2dSq( &i_target ) > 0.0f )
149 DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target ));
150 owner.addUnitState(UNIT_STAT_CHASE);
151 _setTargetLocation(owner, 0);
153 else if ( !owner.HasInArc( 0.0f, &i_target ) )
155 DEBUG_LOG("MOVEMENT : Orientation = %f",owner.GetAngle(&i_target));
156 owner.SetInFront(&i_target);
157 if( i_target.GetTypeId() == TYPEID_PLAYER )
158 owner.SendUpdateToPlayer( (Player*)&i_target );
160 if( !owner.isInCombat() )
162 owner.AIM_Initialize();
166 else if( i_target.isAlive() )
168 if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() )
170 if( spellInfo = owner.reachWithSpellAttack( &i_target ) )
172 _spellAtack(owner, spellInfo);
176 if( owner.GetDistance2dSq( &i_target ) > 0.0f )
178 DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target ));
179 owner.addUnitState(UNIT_STAT_CHASE);
180 _setTargetLocation(owner, 0);
183 else if( !i_targetedHome )
185 if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() && (spellInfo = owner.reachWithSpellAttack(&i_target)) )
187 _spellAtack(owner, spellInfo);
190 _setTargetLocation(owner, 0);
193 if( reach && owner.canReachWithAttack(&i_target) )
196 if(!owner.hasUnitState(UNIT_STAT_FOLLOW))
197 owner.Attack(&i_target);
198 owner.clearUnitState(UNIT_STAT_CHASE);
199 DEBUG_LOG("UNIT IS THERE");
203 _setTargetLocation(owner, 0);
204 DEBUG_LOG("Continue to chase");
210 void TargetedMovementGenerator::_spellAtack(Creature
&owner
, SpellEntry
* spellInfo
)
216 if(owner
.m_currentSpell
)
218 if(owner
.m_currentSpell
->m_spellInfo
->Id
== spellInfo
->Id
)
222 owner
.m_currentSpell
->cancel();
225 Spell
*spell
= new Spell(&owner
, spellInfo
, false, 0);
226 spell
->SetAutoRepeat(true);
227 //owner.addUnitState(UNIT_STAT_ATTACKING);
228 owner
.Attack(&owner
); //??
229 owner
.clearUnitState(UNIT_STAT_CHASE
);
230 SpellCastTargets targets
;
231 targets
.setUnitTarget( &i_target
);
232 spell
->prepare(&targets
);
233 owner
.m_canMove
= false;
234 DEBUG_LOG("Spell Attack.");
237 void TargetedMovementGenerator::spellAtack(Creature
&owner
,Unit
&who
,uint32 spellId
)
239 SpellEntry
*spellInfo
= sSpellStore
.LookupEntry(spellId
);
243 sLog
.outError("WORLD: unknown spell id %i\n", spellId
);
249 if(owner
.m_currentSpell
)
251 if(owner
.m_currentSpell
->m_spellInfo
->Id
== spellInfo
->Id
)
255 owner
.m_currentSpell
->cancel();
258 Spell
*spell
= new Spell(&owner
, spellInfo
, false, 0);
259 spell
->SetAutoRepeat(false);
260 //owner.addUnitState(UNIT_STAT_ATTACKING);
261 //owner.clearUnitState(UNIT_STAT_CHASE);
262 SpellCastTargets targets
;
263 targets
.setUnitTarget( &who
);
264 spell
->prepare(&targets
);
265 owner
.m_canMove
= false;
266 DEBUG_LOG("Spell Attack.");