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

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

[svn] * Improve some arena team related DB access
* Cache GM tickets on server startup.
* Remove unused src/game/HateMatrix.h and references.
* Better check client inventory pos data received in some client packets to
skip invalid cases

Original author: KingPin?
Date: 2008-11-10 09:04:23-06: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.Query("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: %f Y: %f)",
152            guidlow,x,y);
153        return false;
154    }
155
156    Object::_Create(guidlow, 0, HIGHGUID_MO_TRANSPORT);
157
158    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(guidlow);
159
160    if (!goinfo)
161    {
162        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);
163        return false;
164    }
165
166    m_goInfo = goinfo;
167
168    SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
169
170    SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
171    SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
172
173    SetUInt32Value(OBJECT_FIELD_ENTRY, goinfo->id);
174
175    SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId);
176
177    SetGoState(1);
178    SetGoType(GameobjectTypes(goinfo->type));
179
180    SetGoAnimProgress(animprogress);
181    if(dynflags)
182        SetUInt32Value(GAMEOBJECT_DYN_FLAGS, dynflags);
183
184    return true;
185}
186
187struct keyFrame
188{
189    keyFrame(float _x, float _y, float _z, uint32 _mapid, int _actionflag, int _delay)
190    {
191        x = _x; y = _y; z = _z; mapid = _mapid; actionflag = _actionflag; delay = _delay; distFromPrev = -1; distSinceStop = -1; distUntilStop = -1;
192        tFrom = 0; tTo = 0;
193    }
194
195    float x;
196    float y;
197    float z;
198    uint32 mapid;
199    int actionflag;
200    int delay;
201    float distSinceStop;
202    float distUntilStop;
203    float distFromPrev;
204    float tFrom, tTo;
205};
206
207bool Transport::GenerateWaypoints(uint32 pathid, std::set<uint32> &mapids)
208{
209    TransportPath path;
210    objmgr.GetTransportPathNodes(pathid, path);
211
212    if (path.Empty())
213        return false;
214
215    std::vector<keyFrame> keyFrames;
216    int mapChange = 0;
217    mapids.clear();
218    for (size_t i = 1; i < path.Size() - 1; i++)
219    {
220        if (mapChange == 0)
221        {
222            if ((path[i].mapid == path[i+1].mapid))
223            {
224                keyFrame k(path[i].x, path[i].y, path[i].z, path[i].mapid, path[i].actionFlag, path[i].delay);
225                keyFrames.push_back(k);
226                mapids.insert(k.mapid);
227            }
228            else
229            {
230                mapChange = 1;
231            }
232        }
233        else
234        {
235            --mapChange;
236        }
237    }
238
239    int lastStop = -1;
240    int firstStop = -1;
241
242    // first cell is arrived at by teleportation :S
243    keyFrames[0].distFromPrev = 0;
244    if (keyFrames[0].actionflag == 2)
245    {
246        lastStop = 0;
247    }
248
249    // find the rest of the distances between key points
250    for (size_t i = 1; i < keyFrames.size(); i++)
251    {
252        if ((keyFrames[i].actionflag == 1) || (keyFrames[i].mapid != keyFrames[i-1].mapid))
253        {
254            keyFrames[i].distFromPrev = 0;
255        }
256        else
257        {
258            keyFrames[i].distFromPrev =
259                sqrt(pow(keyFrames[i].x - keyFrames[i - 1].x, 2) +
260                pow(keyFrames[i].y - keyFrames[i - 1].y, 2) +
261                pow(keyFrames[i].z - keyFrames[i - 1].z, 2));
262        }
263        if (keyFrames[i].actionflag == 2)
264        {
265            // remember first stop frame
266            if(firstStop == -1)
267                firstStop = i;
268            lastStop = i;
269        }
270    }
271
272    float tmpDist = 0;
273    for (size_t i = 0; i < keyFrames.size(); i++)
274    {
275        int j = (i + lastStop) % keyFrames.size();
276        if (keyFrames[j].actionflag == 2)
277            tmpDist = 0;
278        else
279            tmpDist += keyFrames[j].distFromPrev;
280        keyFrames[j].distSinceStop = tmpDist;
281    }
282
283    for (int i = int(keyFrames.size()) - 1; i >= 0; i--)
284    {
285        int j = (i + (firstStop+1)) % keyFrames.size();
286        tmpDist += keyFrames[(j + 1) % keyFrames.size()].distFromPrev;
287        keyFrames[j].distUntilStop = tmpDist;
288        if (keyFrames[j].actionflag == 2)
289            tmpDist = 0;
290    }
291
292    for (size_t i = 0; i < keyFrames.size(); i++)
293    {
294        if (keyFrames[i].distSinceStop < (30 * 30 * 0.5f))
295            keyFrames[i].tFrom = sqrt(2 * keyFrames[i].distSinceStop);
296        else
297            keyFrames[i].tFrom = ((keyFrames[i].distSinceStop - (30 * 30 * 0.5f)) / 30) + 30;
298
299        if (keyFrames[i].distUntilStop < (30 * 30 * 0.5f))
300            keyFrames[i].tTo = sqrt(2 * keyFrames[i].distUntilStop);
301        else
302            keyFrames[i].tTo = ((keyFrames[i].distUntilStop - (30 * 30 * 0.5f)) / 30) + 30;
303
304        keyFrames[i].tFrom *= 1000;
305        keyFrames[i].tTo *= 1000;
306    }
307
308    //    for (int i = 0; i < keyFrames.size(); i++) {
309    //        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);
310    //    }
311
312    // Now we're completely set up; we can move along the length of each waypoint at 100 ms intervals
313    // speed = max(30, t) (remember x = 0.5s^2, and when accelerating, a = 1 unit/s^2
314    int t = 0;
315    bool teleport = false;
316    if (keyFrames[keyFrames.size() - 1].mapid != keyFrames[0].mapid)
317        teleport = true;
318
319    WayPoint pos(keyFrames[0].mapid, keyFrames[0].x, keyFrames[0].y, keyFrames[0].z, teleport);
320    m_WayPoints[0] = pos;
321    t += keyFrames[0].delay * 1000;
322
323    uint32 cM = keyFrames[0].mapid;
324    for (size_t i = 0; i < keyFrames.size() - 1; i++)
325    {
326        float d = 0;
327        float tFrom = keyFrames[i].tFrom;
328        float tTo = keyFrames[i].tTo;
329
330        // keep the generation of all these points; we use only a few now, but may need the others later
331        if (((d < keyFrames[i + 1].distFromPrev) && (tTo > 0)))
332        {
333            while ((d < keyFrames[i + 1].distFromPrev) && (tTo > 0))
334            {
335                tFrom += 100;
336                tTo -= 100;
337
338                if (d > 0)
339                {
340                    float newX, newY, newZ;
341                    newX = keyFrames[i].x + (keyFrames[i + 1].x - keyFrames[i].x) * d / keyFrames[i + 1].distFromPrev;
342                    newY = keyFrames[i].y + (keyFrames[i + 1].y - keyFrames[i].y) * d / keyFrames[i + 1].distFromPrev;
343                    newZ = keyFrames[i].z + (keyFrames[i + 1].z - keyFrames[i].z) * d / keyFrames[i + 1].distFromPrev;
344
345                    bool teleport = false;
346                    if (keyFrames[i].mapid != cM)
347                    {
348                        teleport = true;
349                        cM = keyFrames[i].mapid;
350                    }
351
352                    //                    sLog.outString("T: %d, D: %f, x: %f, y: %f, z: %f", t, d, newX, newY, newZ);
353                    WayPoint pos(keyFrames[i].mapid, newX, newY, newZ, teleport);
354                    if (teleport)
355                        m_WayPoints[t] = pos;
356                }
357
358                if (tFrom < tTo)                            // caught in tFrom dock's "gravitational pull"
359                {
360                    if (tFrom <= 30000)
361                    {
362                        d = 0.5f * (tFrom / 1000) * (tFrom / 1000);
363                    }
364                    else
365                    {
366                        d = 0.5f * 30 * 30 + 30 * ((tFrom - 30000) / 1000);
367                    }
368                    d = d - keyFrames[i].distSinceStop;
369                }
370                else
371                {
372                    if (tTo <= 30000)
373                    {
374                        d = 0.5f * (tTo / 1000) * (tTo / 1000);
375                    }
376                    else
377                    {
378                        d = 0.5f * 30 * 30 + 30 * ((tTo - 30000) / 1000);
379                    }
380                    d = keyFrames[i].distUntilStop - d;
381                }
382                t += 100;
383            }
384            t -= 100;
385        }
386
387        if (keyFrames[i + 1].tFrom > keyFrames[i + 1].tTo)
388            t += 100 - ((long)keyFrames[i + 1].tTo % 100);
389        else
390            t += (long)keyFrames[i + 1].tTo % 100;
391
392        bool teleport = false;
393        if ((keyFrames[i + 1].actionflag == 1) || (keyFrames[i + 1].mapid != keyFrames[i].mapid))
394        {
395            teleport = true;
396            cM = keyFrames[i + 1].mapid;
397        }
398
399        WayPoint pos(keyFrames[i + 1].mapid, keyFrames[i + 1].x, keyFrames[i + 1].y, keyFrames[i + 1].z, teleport);
400
401        //        sLog.outString("T: %d, x: %f, y: %f, z: %f, t:%d", t, pos.x, pos.y, pos.z, teleport);
402
403        //if (teleport)
404        m_WayPoints[t] = pos;
405
406        t += keyFrames[i + 1].delay * 1000;
407        //        sLog.outString("------");
408    }
409
410    uint32 timer = t;
411
412    //    sLog.outDetail("    Generated %d waypoints, total time %u.", m_WayPoints.size(), timer);
413
414    m_curr = m_WayPoints.begin();
415    m_curr = GetNextWayPoint();
416    m_next = GetNextWayPoint();
417    m_pathTime = timer;
418
419    m_nextNodeTime = m_curr->first;
420
421    return true;
422}
423
424Transport::WayPointMap::iterator Transport::GetNextWayPoint()
425{
426    WayPointMap::iterator iter = m_curr;
427    ++iter;
428    if (iter == m_WayPoints.end())
429        iter = m_WayPoints.begin();
430    return iter;
431}
432
433void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
434{
435    //MapManager::Instance().GetMap(oldMapid)->Remove((GameObject *)this, false);
436    SetMapId(newMapid);
437    //MapManager::Instance().LoadGrid(newMapid,x,y,true);
438    Relocate(x, y, z);
439    //MapManager::Instance().GetMap(newMapid)->Add<GameObject>((GameObject *)this);
440
441    for(PlayerSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();)
442    {
443        PlayerSet::iterator it2 = itr;
444        ++itr;
445
446        Player *plr = *it2;
447        if(!plr)
448        {
449            m_passengers.erase(it2);
450            continue;
451        }
452
453        if (plr->isDead() && !plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
454        {
455            plr->ResurrectPlayer(1.0);
456        }
457        plr->TeleportTo(newMapid, x, y, z, GetOrientation(), TELE_TO_NOT_LEAVE_TRANSPORT);
458
459        //WorldPacket data(SMSG_811, 4);
460        //data << uint32(0);
461        //plr->GetSession()->SendPacket(&data);
462    }
463}
464
465bool Transport::AddPassenger(Player* passenger)
466{
467    if (m_passengers.find(passenger) == m_passengers.end())
468    {
469        sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), this->m_name.c_str());
470        m_passengers.insert(passenger);
471    }
472    return true;
473}
474
475bool Transport::RemovePassenger(Player* passenger)
476{
477    if (m_passengers.find(passenger) != m_passengers.end())
478    {
479        sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), this->m_name.c_str());
480        m_passengers.erase(passenger);
481    }
482    return true;
483}
484
485void Transport::Update(uint32 /*p_time*/)
486{
487    if (m_WayPoints.size() <= 1)
488        return;
489
490    m_timer = getMSTime() % m_period;
491    while (((m_timer - m_curr->first) % m_pathTime) > ((m_next->first - m_curr->first) % m_pathTime))
492    {
493        m_curr = GetNextWayPoint();
494        m_next = GetNextWayPoint();
495
496        // first check help in case client-server transport coordinates de-synchronization
497        if (m_curr->second.mapid != GetMapId() || m_curr->second.teleport)
498        {
499            TeleportTransport(m_curr->second.mapid, m_curr->second.x, m_curr->second.y, m_curr->second.z);
500        }
501        else
502        {
503            //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);
504            Relocate(m_curr->second.x, m_curr->second.y, m_curr->second.z);
505        }
506
507        /*
508        for(PlayerSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();)
509        {
510            PlayerSet::iterator it2 = itr;
511            ++itr;
512            //(*it2)->SetPosition( m_curr->second.x + (*it2)->GetTransOffsetX(), m_curr->second.y + (*it2)->GetTransOffsetY(), m_curr->second.z + (*it2)->GetTransOffsetZ(), (*it2)->GetTransOffsetO() );
513        }
514        */
515
516        m_nextNodeTime = m_curr->first;
517
518        if (m_curr == m_WayPoints.begin() && (sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES)==0)
519            sLog.outDetail(" ************ BEGIN ************** %s", this->m_name.c_str());
520
521        //        MapManager::Instance().GetMap(m_curr->second.mapid)->Add(&this); // -> // ->Add(t);
522        //MapManager::Instance().GetMap(m_curr->second.mapid)->Remove((GameObject *)this, false); // -> // ->Add(t);
523        //MapManager::Instance().GetMap(m_curr->second.mapid)->Add((GameObject *)this); // -> // ->Add(t);
524
525        if ((sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES)==0)
526            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);
527    }
528}
Note: See TracBrowser for help on using the browser.