root/trunk/src/game/Transports.cpp @ 2

Revision 2, 17.1 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include "Common.h"
20
21#include "Transports.h"
22#include "MapManager.h"
23#include "ObjectMgr.h"
24#include "Path.h"
25
26#include "WorldPacket.h"
27#include "Database/DBCStores.h"
28#include "ProgressBar.h"
29
30void MapManager::LoadTransports()
31{
32    QueryResult *result = WorldDatabase.Query("SELECT entry, name, period FROM transports");
33
34    uint32 count = 0;
35
36    if( !result )
37    {
38        barGoLink bar( 1 );
39        bar.step();
40
41        sLog.outString();
42        sLog.outString( ">> Loaded %u transports", count );
43        return;
44    }
45
46    barGoLink bar( result->GetRowCount() );
47
48    do
49    {
50        bar.step();
51
52        Transport *t = new Transport;
53
54        Field *fields = result->Fetch();
55
56        uint32 entry = fields[0].GetUInt32();
57        std::string name = fields[1].GetCppString();
58        t->m_period = fields[2].GetUInt32();
59
60        const GameObjectInfo *goinfo = objmgr.GetGameObjectInfo(entry);
61
62        if(!goinfo)
63        {
64            sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template missing", entry, name.c_str());
65            delete t;
66            continue;
67        }
68
69        if(goinfo->type != GAMEOBJECT_TYPE_MO_TRANSPORT)
70        {
71            sLog.outErrorDb("Transport ID:%u, Name: %s, will not be loaded, gameobject_template type wrong", entry, name.c_str());
72            delete t;
73            continue;
74        }
75
76        // sLog.outString("Loading transport %d between %s, %s", entry, name.c_str(), goinfo->name);
77
78        std::set<uint32> mapsUsed;
79
80        if(!t->GenerateWaypoints(goinfo->moTransport.taxiPathId, mapsUsed))
81            // skip transports with empty waypoints list
82        {
83            sLog.outErrorDb("Transport (path id %u) path size = 0. Transport ignored, check DBC files or transport GO data0 field.",goinfo->moTransport.taxiPathId);
84            delete t;
85            continue;
86        }
87
88        t->m_name = goinfo->name;
89
90        float x, y, z, o;
91        uint32 mapid;
92        x = t->m_WayPoints[0].x; y = t->m_WayPoints[0].y; z = t->m_WayPoints[0].z; mapid = t->m_WayPoints[0].mapid; o = 1;
93
94                                                            // creates the Gameobject
95        if(!t->Create(entry, mapid, x, y, z, o, 100, 0))
96        {
97            delete t;
98            continue;
99        }
100
101        m_Transports.insert(t);
102
103        for (std::set<uint32>::iterator i = mapsUsed.begin(); i != mapsUsed.end(); ++i)
104            m_TransportsByMap[*i].insert(t);
105
106        //If we someday decide to use the grid to track transports, here:
107        //MapManager::Instance().LoadGrid(mapid,x,y,true);
108        //MapManager::Instance().GetMap(t->GetMapId())->Add<GameObject>((GameObject *)t);
109        ++count;
110    } while(result->NextRow());
111    delete result;
112
113    sLog.outString();
114    sLog.outString( ">> Loaded %u transports", count );
115
116    // check transport data DB integrity
117    result = WorldDatabase.PQuery("SELECT gameobject.guid,gameobject.id,transports.name FROM gameobject,transports WHERE gameobject.id = transports.entry");
118    if(result)                                              // wrong data found
119    {
120        do
121        {
122            Field *fields = result->Fetch();
123
124            uint32 guid  = fields[0].GetUInt32();
125            uint32 entry = fields[1].GetUInt32();
126            std::string name = fields[2].GetCppString();
127            sLog.outErrorDb("Transport %u '%s' have record (GUID: %u) in `gameobject`. Transports DON'T must have any records in `gameobject` or its behavior will be unpredictable/bugged.",entry,name.c_str(),guid);
128        }
129        while(result->NextRow());
130
131        delete result;
132    }
133}
134
135Transport::Transport() : GameObject()
136{
137                                                            // 2.3.2 - 0x5A
138    m_updateFlag = (UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
139}
140
141bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags)
142{
143    Relocate(x,y,z,ang);
144
145    SetMapId(mapid);
146
147    if(!IsPositionValid())
148    {
149        sLog.outError("ERROR: Transport (GUID: %u) not created. Suggested coordinates isn't valid (X: %d Y: ^%d)",guidlow,x,y);
150        return false;
151    }
152
153    Object::_Create(guidlow, 0, HIGHGUID_MO_TRANSPORT);
154
155    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(guidlow);
156
157    if (!goinfo)
158    {
159        sLog.outErrorDb("Transport not created: entry in `gameobject_template` not found, guidlow: %u map: %u  (X: %f Y: %f Z: %f) ang: %f",guidlow, mapid, x, y, z, ang);
160        return false;
161    }
162
163    m_goInfo = goinfo;
164
165    SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
166
167    SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
168    SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
169
170    SetUInt32Value(OBJECT_FIELD_ENTRY, goinfo->id);
171
172    SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId);
173
174    SetGoState(1);
175    SetGoType(GameobjectTypes(goinfo->type));
176
177    SetGoAnimProgress(animprogress);
178    if(dynflags)
179        SetUInt32Value(GAMEOBJECT_DYN_FLAGS, dynflags);
180
181    return true;
182}
183
184struct keyFrame
185{
186    keyFrame(float _x, float _y, float _z, uint32 _mapid, int _actionflag, int _delay)
187    {
188        x = _x; y = _y; z = _z; mapid = _mapid; actionflag = _actionflag; delay = _delay; distFromPrev = -1; distSinceStop = -1; distUntilStop = -1;
189        tFrom = 0; tTo = 0;
190    }
191
192    float x;
193    float y;
194    float z;
195    uint32 mapid;
196    int actionflag;
197    int delay;
198    float distSinceStop;
199    float distUntilStop;
200    float distFromPrev;
201    float tFrom, tTo;
202};
203
204bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
205{
206    TransportPath path;
207    objmgr.GetTransportPathNodes(pathid, path);
208
209    if (path.Empty())
210        return false;
211
212    std::vector<keyFrame> keyFrames;
213    int mapChange = 0;
214    mapids.clear();
215    for (size_t i = 1; i < path.Size() - 1; i++)
216    {
217        if (mapChange == 0)
218        {
219            if ((path[i].mapid == path[i+1].mapid))
220            {
221                keyFrame k(path[i].x, path[i].y, path[i].z, path[i].mapid, path[i].actionFlag, path[i].delay);
222                keyFrames.push_back(k);
223                mapids.insert(k.mapid);
224            }
225            else
226            {
227                mapChange = 1;
228            }
229        }
230        else
231        {
232            --mapChange;
233        }
234    }
235
236    int lastStop = -1;
237    int firstStop = -1;
238
239    // first cell is arrived at by teleportation :S
240    keyFrames[0].distFromPrev = 0;
241    if (keyFrames[0].actionflag == 2)
242    {
243        lastStop = 0;
244    }
245
246    // find the rest of the distances between key points
247    for (size_t i = 1; i < keyFrames.size(); i++)
248    {
249        if ((keyFrames[i].actionflag == 1) || (keyFrames[i].mapid != keyFrames[i-1].mapid))
250        {
251            keyFrames[i].distFromPrev = 0;
252        }
253        else
254        {
255            keyFrames[i].distFromPrev =
256                sqrt(pow(keyFrames[i].x - keyFrames[i - 1].x, 2) +
257                pow(keyFrames[i].y - keyFrames[i - 1].y, 2) +
258                pow(keyFrames[i].z - keyFrames[i - 1].z, 2));
259        }
260        if (keyFrames[i].actionflag == 2)
261        {
262            // remember first stop frame
263            if(firstStop == -1)
264                firstStop = i;
265            lastStop = i;
266        }
267    }
268
269    float tmpDist = 0;
270    for (size_t i = 0; i < keyFrames.size(); i++)
271    {
272        int j = (i + lastStop) % keyFrames.size();
273        if (keyFrames[j].actionflag == 2)
274            tmpDist = 0;
275        else
276            tmpDist += keyFrames[j].distFromPrev;
277        keyFrames[j].distSinceStop = tmpDist;
278    }
279
280    for (int i = int(keyFrames.size()) - 1; i >= 0; i--)
281    {
282        int j = (i + (firstStop+1)) % keyFrames.size();
283        tmpDist += keyFrames[(j + 1) % keyFrames.size()].distFromPrev;
284        keyFrames[j].distUntilStop = tmpDist;
285        if (keyFrames[j].actionflag == 2)
286            tmpDist = 0;
287    }
288
289    for (size_t i = 0; i < keyFrames.size(); i++)
290    {
291        if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f))
292            keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop);
293        else
294            keyFrames[i].tFrom = ((keyFrames[i].distSinceStop - (30 * 30 * 0.5f)) / 30) + 30;
295
296        if (keyFrames[i].distUntilStop < (30 * 30 * 0.5f))
297            keyFrames[i].tTo = sqrt(2 * keyFrames[i].distUntilStop);
298        else
299            keyFrames[i].tTo = ((keyFrames[i].distUntilStop - (30 * 30 * 0.5f)) / 30) + 30;
300
301        keyFrames[i].tFrom *= 1000;
302        keyFrames[i].tTo *= 1000;
303    }
304
305    //    for (int i = 0; i < keyFrames.size(); i++) {
306    //        sLog.outString("%f, %f, %f, %f, %f, %f, %f", keyFrames[i].x, keyFrames[i].y, keyFrames[i].distUntilStop, keyFrames[i].distSinceStop, keyFrames[i].distFromPrev, keyFrames[i].tFrom, keyFrames[i].tTo);
307    //    }
308
309    // Now we're completely set up; we can move along the length of each waypoint at 100 ms intervals
310    // speed = max(30, t) (remember x = 0.5s^2, and when accelerating, a = 1 unit/s^2
311    int t = 0;
312    bool teleport = false;
313    if (keyFrames[keyFrames.size() - 1].mapid != keyFrames[0].mapid)
314        teleport = true;
315
316    WayPoint pos(keyFrames[0].mapid, keyFrames[0].x, keyFrames[0].y, keyFrames[0].z, teleport);
317    m_WayPoints[0] = pos;
318    t += keyFrames[0].delay * 1000;
319
320    uint32 cM = keyFrames[0].mapid;
321    for (size_t i = 0; i < keyFrames.size() - 1; i++)
322    {
323        float d = 0;
324        float tFrom = keyFrames[i].tFrom;
325        float tTo = keyFrames[i].tTo;
326
327        // keep the generation of all these points; we use only a few now, but may need the others later
328        if (((d < keyFrames[i + 1].distFromPrev) && (tTo > 0)))
329        {
330            while ((d < keyFrames[i + 1].distFromPrev) && (tTo > 0))
331            {
332                tFrom += 100;
333                tTo -= 100;
334
335                if (d > 0)
336                {
337                    float newX, newY, newZ;
338                    newX = keyFrames[i].x + (keyFrames[i + 1].x - keyFrames[i].x) * d / keyFrames[i + 1].distFromPrev;
339                    newY = keyFrames[i].y + (keyFrames[i + 1].y - keyFrames[i].y) * d / keyFrames[i + 1].distFromPrev;
340                    newZ = keyFrames[i].z + (keyFrames[i + 1].z - keyFrames[i].z) * d / keyFrames[i + 1].distFromPrev;
341
342                    bool teleport = false;
343                    if (keyFrames[i].mapid != cM)
344                    {
345                        teleport = true;
346                        cM = keyFrames[i].mapid;
347                    }
348
349                    //                    sLog.outString("T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ);
350                    WayPoint pos(keyFrames[i].mapid, newX, newY, newZ, teleport);
351                    if (teleport)
352                        m_WayPoints[t] = pos;
353                }
354
355                if (tFrom < tTo)                            // caught in tFrom dock's "gravitational pull"
356                {
357                    if (tFrom <= 30000)
358                    {
359                        d = 0.5f * (tFrom / 1000) * (tFrom / 1000);
360                    }
361                    else
362                    {
363                        d = 0.5f * 30 * 30 + 30 * ((tFrom - 30000) / 1000);
364                    }
365                    d = d - keyFrames[i].distSinceStop;
366                }
367                else
368                {
369                    if (tTo <= 30000)
370                    {
371                        d = 0.5f * (tTo / 1000) * (tTo / 1000);
372                    }
373                    else
374                    {
375                        d = 0.5f * 30 * 30 + 30 * ((tTo - 30000) / 1000);
376                    }
377                    d = keyFrames[i].distUntilStop - d;
378                }
379                t += 100;
380            }
381            t -= 100;
382        }
383
384        if (keyFrames[i + 1].tFrom > keyFrames[i + 1].tTo)
385            t += 100 - ((long)keyFrames[i + 1].tTo % 100);
386        else
387            t += (long)keyFrames[i + 1].tTo % 100;
388
389        bool teleport = false;
390        if ((keyFrames[i + 1].actionflag == 1) || (keyFrames[i + 1].mapid != keyFrames[i].mapid))
391        {
392            teleport = true;
393            cM = keyFrames[i + 1].mapid;
394        }
395
396        WayPoint pos(keyFrames[i + 1].mapid, keyFrames[i + 1].x, keyFrames[i + 1].y, keyFrames[i + 1].z, teleport);
397
398        //        sLog.outString("T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport);
399
400        //if (teleport)
401        m_WayPoints[t] = pos;
402
403        t += keyFrames[i + 1].delay * 1000;
404        //        sLog.outString("------");
405    }
406
407    uint32 timer = t;
408
409    //    sLog.outDetail("    Generated %d waypoints, total time %u.", m_WayPoints.size(), timer);
410
411    m_curr = m_WayPoints.begin();
412    m_curr = GetNextWayPoint();
413    m_next = GetNextWayPoint();
414    m_pathTime = timer;
415
416    m_nextNodeTime = m_curr->first;
417
418    return true;
419}
420
421Transport::WayPointMap::iterator Transport::GetNextWayPoint()
422{
423    WayPointMap::iterator iter = m_curr;
424    ++iter;
425    if (iter == m_WayPoints.end())
426        iter = m_WayPoints.begin();
427    return iter;
428}
429
430void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
431{
432    //MapManager::Instance().GetMap(oldMapid)->Remove((GameObject *)this, false);
433    SetMapId(newMapid);
434    //MapManager::Instance().LoadGrid(newMapid,x,y,true);
435    Relocate(x, y, z);
436    //MapManager::Instance().GetMap(newMapid)->Add<GameObject>((GameObject *)this);
437
438    for(PlayerSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();)
439    {
440        PlayerSet::iterator it2 = itr;
441        ++itr;
442
443        Player *plr = *it2;
444        if(!plr)
445        {
446            m_passengers.erase(it2);
447            continue;
448        }
449
450        if (plr->isDead() && !plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
451        {
452            plr->ResurrectPlayer(1.0);
453        }
454        plr->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT);
455
456        //WorldPacket data(SMSG_811, 4);
457        //data << uint32(0);
458        //plr->GetSession()->SendPacket(&data);
459    }
460}
461
462bool Transport::AddPassenger(Player* passenger)
463{
464    if (m_passengers.find(passenger) == m_passengers.end())
465    {
466        sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), this->m_name.c_str());
467        m_passengers.insert(passenger);
468    }
469    return true;
470}
471
472bool Transport::RemovePassenger(Player* passenger)
473{
474    if (m_passengers.find(passenger) != m_passengers.end())
475    {
476        sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), this->m_name.c_str());
477        m_passengers.erase(passenger);
478    }
479    return true;
480}
481
482void Transport::Update(uint32 /*p_time*/)
483{
484    if (m_WayPoints.size() <= 1)
485        return;
486
487    m_timer = getMSTime() % m_period;
488    while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime))
489    {
490        m_curr = GetNextWayPoint();
491        m_next = GetNextWayPoint();
492
493        // first check help in case client-server transport coordinates de-synchronization
494        if (m_curr->second.mapid != GetMapId() || m_curr->second.teleport)
495        {
496            TeleportTransport(m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z);
497        }
498        else
499        {
500            //MapManager::Instance().GetMap(m_curr->second.mapid)->GameobjectRelocation((GameObject *)this, m_curr->second.x, m_curr->second.y, m_curr->second.z, this->m_orientation);
501            Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z);
502        }
503
504        /*
505        for(PlayerSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();)
506        {
507            PlayerSet::iterator it2 = itr;
508            ++itr;
509            //(*it2)->SetPosition( m_curr->second.x + (*it2)->GetTransOffsetX(), m_curr->second.y + (*it2)->GetTransOffsetY(), m_curr->second.z + (*it2)->GetTransOffsetZ(), (*it2)->GetTransOffsetO() );
510        }
511        */
512
513        m_nextNodeTime = m_curr->first;
514
515        if (m_curr == m_WayPoints.begin() && (sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES)==0)
516            sLog.outDetail(" ************ BEGIN ************** %s", this->m_name.c_str());
517
518        //        MapManager::Instance().GetMap(m_curr->second.mapid)->Add(&this); // -> // ->Add(t);
519        //MapManager::Instance().GetMap(m_curr->second.mapid)->Remove((GameObject *)this, false); // -> // ->Add(t);
520        //MapManager::Instance().GetMap(m_curr->second.mapid)->Add((GameObject *)this); // -> // ->Add(t);
521
522        if ((sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES)==0)
523            sLog.outDetail("%s moved to %f %f %f %d", this->m_name.c_str(), m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid);
524    }
525}
Note: See TracBrowser for help on using the browser.