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

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

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-05:00

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