aboutsummaryrefslogtreecommitdiff
path: root/src/game/DestinationHolderImp.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/DestinationHolderImp.h')
-rw-r--r--src/game/DestinationHolderImp.h243
1 files changed, 243 insertions, 0 deletions
diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h
new file mode 100644
index 00000000000..8f5efa54b0c
--- /dev/null
+++ b/src/game/DestinationHolderImp.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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
+ */
+
+#ifndef MANGOS_DESTINATIONHOLDERIMP_H
+#define MANGOS_DESTINATIONHOLDERIMP_H
+
+#include "Creature.h"
+#include "MapManager.h"
+#include "DestinationHolder.h"
+
+#include <cmath>
+
+template<typename TRAVELLER>
+void
+DestinationHolder<TRAVELLER>::_findOffSetPoint(float x1, float y1, float x2, float y2, float offset, float &x, float &y)
+{
+ /* given the point (x1, y1) and (x2, y2).. need to find the point (x,y) on the same line
+ * such that the distance from (x, y) to (x2, y2) is offset.
+ * Let the distance of p1 to p2 = d.. then the ratio of offset/d = (x2-x)/(x2-x1)
+ * hence x = x2 - (offset/d)*(x2-x1)
+ * like wise offset/d = (y2-y)/(y2-y1);
+ */
+ if( offset == 0 )
+ {
+ x = x2;
+ y = y2;
+ }
+ else
+ {
+ double x_diff = double(x2 - x1);
+ double y_diff = double(y2 - y1);
+ double distance_d = (double)((x_diff*x_diff) + (y_diff * y_diff));
+ if(distance_d == 0)
+ {
+ x = x2;
+ y = y2;
+ }
+ else
+ {
+ distance_d = ::sqrt(distance_d); // starting distance
+ double distance_ratio = (double)(distance_d - offset)/(double)distance_d;
+ // line above has revised formula which is more correct, I think
+ x = (float)(x1 + (distance_ratio*x_diff));
+ y = (float)(y1 + (distance_ratio*y_diff));
+ }
+ }
+}
+
+template<typename TRAVELLER>
+uint32
+DestinationHolder<TRAVELLER>::SetDestination(TRAVELLER &traveller, float dest_x, float dest_y, float dest_z, bool sendMove)
+{
+ i_destSet = true;
+ i_destX = dest_x;
+ i_destY = dest_y;
+ i_destZ = dest_z;
+
+ return StartTravel(traveller, sendMove);
+}
+
+template<typename TRAVELLER>
+uint32
+DestinationHolder<TRAVELLER>::StartTravel(TRAVELLER &traveller, bool sendMove)
+{
+ if(!i_destSet) return 0;
+
+ i_fromX = traveller.GetPositionX();
+ i_fromY = traveller.GetPositionY();
+ i_fromZ = traveller.GetPositionZ();
+
+ float dx = i_destX - i_fromX;
+ float dy = i_destY - i_fromY;
+ float dz = i_destZ - i_fromZ;
+
+ float dist;
+ //Should be for Creature Flying and Swimming.
+ if(traveller.GetTraveller().hasUnitState(UNIT_STAT_IN_FLIGHT))
+ dist = sqrt((dx*dx) + (dy*dy) + (dz*dz));
+ else //Walking on the ground
+ dist = sqrt((dx*dx) + (dy*dy));
+ float speed = traveller.Speed();
+
+ speed *= 0.001f; // speed is in seconds so convert from second to millisecond
+ i_totalTravelTime = static_cast<uint32>(dist/speed);
+ i_timeElapsed = 0;
+ if(sendMove)
+ traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime);
+ return i_totalTravelTime;
+}
+
+template<typename TRAVELLER>
+bool
+DestinationHolder<TRAVELLER>::UpdateTraveller(TRAVELLER &traveller, uint32 diff, bool force_update, bool micro_movement)
+{
+ if(!micro_movement)
+ {
+ i_tracker.Update(diff);
+ i_timeElapsed += diff;
+ if( i_tracker.Passed() || force_update )
+ {
+ ResetUpdate();
+ if(!i_destSet) return true;
+ float x,y,z;
+ GetLocationNowNoMicroMovement(x, y, z);
+ if( x == -431602080 )
+ return false;
+ if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y )
+ {
+ float ori = traveller.GetTraveller().GetAngle(x, y);
+ traveller.Relocation(x, y, z, ori);
+ }
+ return true;
+ }
+ return false;
+ }
+ i_tracker.Update(diff);
+ i_timeElapsed += diff;
+ if( i_tracker.Passed() || force_update )
+ {
+ ResetUpdate();
+ if(!i_destSet) return true;
+ float x,y,z;
+
+ if(!traveller.GetTraveller().hasUnitState(UNIT_STAT_MOVING | UNIT_STAT_IN_FLIGHT))
+ return true;
+
+ if(traveller.GetTraveller().hasUnitState(UNIT_STAT_IN_FLIGHT))
+ GetLocationNow(traveller.GetTraveller().GetMapId() ,x, y, z, true); // Should repositione Object with right Coord, so I can bypass some Grid Relocation
+ else
+ GetLocationNow(traveller.GetTraveller().GetMapId(), x, y, z, false);
+
+ if( x == -431602080 )
+ return false;
+
+ if( traveller.GetTraveller().GetPositionX() != x || traveller.GetTraveller().GetPositionY() != y )
+ {
+ float ori = traveller.GetTraveller().GetAngle(x, y);
+ traveller.Relocation(x, y, z, ori);
+ }
+ // Change movement computation to micro movement based on last tick coords, this makes system work
+ // even on multiple floors zones without hugh vmaps usage ;)
+
+ // Take care of underrun of uint32
+ if (i_totalTravelTime >= i_timeElapsed)
+ i_totalTravelTime -= i_timeElapsed; // Consider only the remaining part
+ else
+ i_totalTravelTime = 0;
+
+ i_timeElapsed = 0;
+ i_fromX = x; // and change origine
+ i_fromY = y; // then I take into account only micro movement
+ i_fromZ = z;
+ return true;
+ }
+ return false;
+}
+
+template<typename TRAVELLER>
+void
+DestinationHolder<TRAVELLER>::GetLocationNow(uint32 mapid, float &x, float &y, float &z, bool is3D) const
+{
+ if( HasArrived() )
+ {
+ x = i_destX;
+ y = i_destY;
+ z = i_destZ;
+ }
+ else if(HasDestination())
+ {
+ double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
+ const float distanceX = ((i_destX - i_fromX) * percent_passed);
+ const float distanceY = ((i_destY - i_fromY) * percent_passed);
+ const float distanceZ = ((i_destZ - i_fromZ) * percent_passed);
+ x = i_fromX + distanceX;
+ y = i_fromY + distanceY;
+ float z2 = i_fromZ + distanceZ;
+ // All that is not finished but previous code neither... Traveller need be able to swim.
+ if(is3D)
+ z = z2;
+ else
+ {
+ //That part is good for mob Walking on the floor. But the floor is not allways what we thought.
+ z = MapManager::Instance().GetBaseMap(mapid)->GetHeight(x,y,i_fromZ,false); // Disable cave check
+ const float groundDist = sqrt(distanceX*distanceX + distanceY*distanceY);
+ const float zDist = fabs(i_fromZ - z) + 0.000001f;
+ const float slope = groundDist / zDist;
+ if(slope < 1.0f) // This prevents the ground returned by GetHeight to be used when in cave
+ z = z2; // a climb or jump of more than 45 is denied
+ }
+ }
+}
+
+template<typename TRAVELLER>
+float
+DestinationHolder<TRAVELLER>::GetDistance2dFromDestSq(const WorldObject &obj) const
+{
+ float x,y,z;
+ obj.GetPosition(x,y,z);
+ return (i_destX-x)*(i_destX-x)+(i_destY-y)*(i_destY-y);
+}
+
+template<typename TRAVELLER>
+float
+DestinationHolder<TRAVELLER>::GetDestinationDiff(float x, float y, float z) const
+{
+ return sqrt(((x-i_destX)*(x-i_destX)) + ((y-i_destY)*(y-i_destY)) + ((z-i_destZ)*(z-i_destZ)));
+}
+
+template<typename TRAVELLER>
+void
+DestinationHolder<TRAVELLER>::GetLocationNowNoMicroMovement(float &x, float &y, float &z) const
+{
+ if( HasArrived() )
+ {
+ x = i_destX;
+ y = i_destY;
+ z = i_destZ;
+ }
+ else
+ {
+ double percent_passed = (double)i_timeElapsed / (double)i_totalTravelTime;
+ x = i_fromX + ((i_destX - i_fromX) * percent_passed);
+ y = i_fromY + ((i_destY - i_fromY) * percent_passed);
+ z = i_fromZ + ((i_destZ - i_fromZ) * percent_passed);
+ }
+}
+
+#endif