root/trunk/src/game/GameObject.cpp @ 203

Revision 203, 45.3 kB (checked in by yumileroy, 17 years ago)

[svn] Send AttackStart? package when update visibility.
Update DoMeleeAttackIfReady? to support dual wield.
Show player modelid2 instead id3 of triggers. This should fix the bug that gameobject::castspell summon a human model.
Remove the correct flag to make creature attackable. This should fix the bug that Illidan and Magtheridon are unattackable.
Add NullCreatureAI for trinityscript.
Fix channeler's soul transfer.
Some update of black temple scripts.

Original author: megamage
Date: 2008-11-09 14:54:13-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#include "QuestDef.h"
23#include "GameObject.h"
24#include "ObjectMgr.h"
25#include "SpellMgr.h"
26#include "Spell.h"
27#include "UpdateMask.h"
28#include "Opcodes.h"
29#include "WorldPacket.h"
30#include "WorldSession.h"
31#include "World.h"
32#include "Database/DatabaseEnv.h"
33#include "MapManager.h"
34#include "LootMgr.h"
35#include "GridNotifiers.h"
36#include "GridNotifiersImpl.h"
37#include "CellImpl.h"
38#include "InstanceData.h"
39#include "BattleGround.h"
40#include "OutdoorPvPMgr.h"
41#include "Util.h"
42
43GameObject::GameObject() : WorldObject()
44{
45    m_objectType |= TYPEMASK_GAMEOBJECT;
46    m_objectTypeId = TYPEID_GAMEOBJECT;
47                                                            // 2.3.2 - 0x58
48    m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_HASPOSITION);
49
50    m_valuesCount = GAMEOBJECT_END;
51    m_respawnTime = 0;
52    m_respawnDelayTime = 25;
53    m_lootState = GO_NOT_READY;
54    m_spawnedByDefault = true;
55    m_usetimes = 0;
56    m_spellId = 0;
57    m_charges = 5;
58    m_cooldownTime = 0;
59    m_goInfo = NULL;
60
61    m_DBTableGuid = 0;
62}
63
64GameObject::~GameObject()
65{
66    if(m_uint32Values)                                      // field array can be not exist if GameOBject not loaded
67    {
68        // crash possable at access to deleted GO in Unit::m_gameobj
69        uint64 owner_guid = GetOwnerGUID();
70        if(owner_guid)
71        {
72            Unit* owner = ObjectAccessor::GetUnit(*this,owner_guid);
73            if(owner)
74                owner->RemoveGameObject(this,false);
75            else if(!IS_PLAYER_GUID(owner_guid))
76                sLog.outError("Delete GameObject (GUID: %u Entry: %u ) that have references in not found creature %u GO list. Crash possable later.",GetGUIDLow(),GetGOInfo()->id,GUID_LOPART(owner_guid));
77        }
78    }
79}
80
81void GameObject::AddToWorld()
82{
83    ///- Register the gameobject for guid lookup
84    if(!IsInWorld()) ObjectAccessor::Instance().AddObject(this);
85    WorldObject::AddToWorld();
86}
87
88void GameObject::RemoveFromWorld()
89{
90    ///- Remove the gameobject from the accessor
91    if(IsInWorld()) ObjectAccessor::Instance().RemoveObject(this);
92    WorldObject::RemoveFromWorld();
93}
94
95bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, uint32 go_state, uint32 ArtKit)
96{
97    Relocate(x,y,z,ang);
98    SetMapId(map->GetId());
99    SetInstanceId(map->GetInstanceId());
100
101    if(!IsPositionValid())
102    {
103        sLog.outError("ERROR: Gameobject (GUID: %u Entry: %u ) not created. Suggested coordinates isn't valid (X: %f Y: %f)",guidlow,name_id,x,y);
104        return false;
105    }
106
107    GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
108    if (!goinfo)
109    {
110        sLog.outErrorDb("Gameobject (GUID: %u Entry: %u) not created: it have not exist entry in `gameobject_template`. Map: %u  (X: %f Y: %f Z: %f) ang: %f rotation0: %f rotation1: %f rotation2: %f rotation3: %f",guidlow, name_id, map->GetId(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3);
111        return false;
112    }
113
114    Object::_Create(guidlow, goinfo->id, HIGHGUID_GAMEOBJECT);
115
116    m_goInfo = goinfo;
117
118    if (goinfo->type >= MAX_GAMEOBJECT_TYPE)
119    {
120        sLog.outErrorDb("Gameobject (GUID: %u Entry: %u) not created: it have not exist GO type '%u' in `gameobject_template`. It's will crash client if created.",guidlow,name_id,goinfo->type);
121        return false;
122    }
123
124    SetFloatValue(GAMEOBJECT_POS_X, x);
125    SetFloatValue(GAMEOBJECT_POS_Y, y);
126    SetFloatValue(GAMEOBJECT_POS_Z, z);
127    SetFloatValue(GAMEOBJECT_FACING, ang);                  //this is not facing angle
128
129    SetFloatValue (GAMEOBJECT_ROTATION, rotation0);
130    SetFloatValue (GAMEOBJECT_ROTATION+1, rotation1);
131    SetFloatValue (GAMEOBJECT_ROTATION+2, rotation2);
132    SetFloatValue (GAMEOBJECT_ROTATION+3, rotation3);
133
134    SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size);
135
136    SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
137    SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
138
139    SetUInt32Value(OBJECT_FIELD_ENTRY, goinfo->id);
140
141    SetUInt32Value(GAMEOBJECT_DISPLAYID, goinfo->displayId);
142
143    SetGoState(go_state);
144    SetGoType(GameobjectTypes(goinfo->type));
145
146    SetGoAnimProgress(animprogress);
147
148    SetUInt32Value (GAMEOBJECT_ARTKIT, ArtKit);
149
150    // Spell charges for GAMEOBJECT_TYPE_SPELLCASTER (22)
151    if (goinfo->type == GAMEOBJECT_TYPE_SPELLCASTER)
152        m_charges = goinfo->spellcaster.charges;
153
154    //Notify the map's instance data.
155    //Only works if you create the object in it, not if it is moves to that map.
156    //Normally non-players do not teleport to other maps.
157    if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
158    {
159        ((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this);
160    }
161
162    return true;
163}
164
165void GameObject::Update(uint32 /*p_time*/)
166{
167    if (IS_MO_TRANSPORT(GetGUID()))
168    {
169        //((Transport*)this)->Update(p_time);
170        return;
171    }
172
173    switch (m_lootState)
174    {
175        case GO_NOT_READY:
176        {
177            switch(GetGoType())
178            {
179                case GAMEOBJECT_TYPE_TRAP:
180                {
181                    // Arming Time for GAMEOBJECT_TYPE_TRAP (6)
182                    Unit* owner = GetOwner();
183                    if (owner && ((Player*)owner)->isInCombat())
184                        m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay;
185                    m_lootState = GO_READY;
186                    break;
187                }
188                case GAMEOBJECT_TYPE_FISHINGNODE:
189                {
190                    // fishing code (bobber ready)
191                    if( time(NULL) > m_respawnTime - FISHING_BOBBER_READY_TIME )
192                    {
193                        // splash bobber (bobber ready now)
194                        Unit* caster = GetOwner();
195                        if(caster && caster->GetTypeId()==TYPEID_PLAYER)
196                        {
197                            SetGoState(0);
198                            SetUInt32Value(GAMEOBJECT_FLAGS, 32);
199
200                            UpdateData udata;
201                            WorldPacket packet;
202                            BuildValuesUpdateBlockForPlayer(&udata,((Player*)caster));
203                            udata.BuildPacket(&packet);
204                            ((Player*)caster)->GetSession()->SendPacket(&packet);
205
206                            WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4);
207                            data << GetGUID();
208                            data << (uint32)(0);
209                            ((Player*)caster)->SendMessageToSet(&data,true);
210                        }
211
212                        m_lootState = GO_READY;                 // can be succesfully open with some chance
213                    }
214                    return;
215                }
216                default:
217                    m_lootState = GO_READY;                         // for other GOis same switched without delay to GO_READY
218                    break;
219            }
220            // NO BREAK for switch (m_lootState)
221        }
222        case GO_READY:
223        {
224            if (m_respawnTime > 0)                          // timer on
225            {
226                if (m_respawnTime <= time(NULL))            // timer expired
227                {
228                    m_respawnTime = 0;
229                    m_SkillupList.clear();
230                    m_usetimes = 0;
231
232                    switch (GetGoType())
233                    {
234                        case GAMEOBJECT_TYPE_FISHINGNODE:   //  can't fish now
235                        {
236                            Unit* caster = GetOwner();
237                            if(caster && caster->GetTypeId()==TYPEID_PLAYER)
238                            {
239                                if(caster->m_currentSpells[CURRENT_CHANNELED_SPELL])
240                                {
241                                    caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
242                                    caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->finish(false);
243                                }
244
245                                WorldPacket data(SMSG_FISH_NOT_HOOKED,0);
246                                ((Player*)caster)->GetSession()->SendPacket(&data);
247                            }
248                            // can be delete
249                            m_lootState = GO_JUST_DEACTIVATED;
250                            return;
251                        }
252                        case GAMEOBJECT_TYPE_DOOR:
253                        case GAMEOBJECT_TYPE_BUTTON:
254                            //we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds)
255                            if( !GetGoState() )
256                                SwitchDoorOrButton(false);
257                            //flags in AB are type_button and we need to add them here so no break!
258                        default:
259                            if(!m_spawnedByDefault)         // despawn timer
260                            {
261                                                            // can be despawned or destroyed
262                                SetLootState(GO_JUST_DEACTIVATED);
263                                return;
264                            }
265                                                            // respawn timer
266                            MapManager::Instance().GetMap(GetMapId(), this)->Add(this);
267                            break;
268                    }
269                }
270            }
271
272            // traps can have time and can not have
273            GameObjectInfo const* goInfo = GetGOInfo();
274            if(goInfo->type == GAMEOBJECT_TYPE_TRAP)
275            {
276                // traps
277                Unit* owner = GetOwner();
278                Unit* ok = NULL;                            // pointer to appropriate target if found any
279
280                if(m_cooldownTime >= time(NULL))
281                    return;
282
283                bool IsBattleGroundTrap = false;
284                //FIXME: this is activation radius (in different casting radius that must be selected from spell data)
285                //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state
286                float radius = goInfo->trap.radius;
287                if(!radius)
288                {
289                    if(goInfo->trap.cooldown != 3)            // cast in other case (at some triggring/linked go/etc explicit call)
290                        return;
291                    else
292                    {
293                        if(m_respawnTime > 0)
294                            break;
295
296                        radius = goInfo->trap.cooldown;       // battlegrounds gameobjects has data2 == 0 && data5 == 3
297                        IsBattleGroundTrap = true;
298                    }
299                }
300
301                bool NeedDespawn = (goInfo->trap.charges != 0);
302
303                CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY()));
304                Cell cell(p);
305                cell.data.Part.reserved = ALL_DISTRICT;
306
307                // Note: this hack with search required until GO casting not implemented
308                // search unfriendly creature
309                if(owner && NeedDespawn)                    // hunter trap
310                {
311                    Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, owner, radius);
312                    Trinity::UnitSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> checker(ok, u_check);
313
314                    CellLock<GridReadGuard> cell_lock(cell, p);
315
316                    TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker);
317                    cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
318
319                    // or unfriendly player/pet
320                    if(!ok)
321                    {
322                        TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker);
323                        cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
324                    }
325                }
326                else                                        // environmental trap
327                {
328                    // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support
329
330                    // affect only players
331                    Player* p_ok = NULL;
332                    Trinity::AnyPlayerInObjectRangeCheck p_check(this, radius);
333                    Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck>  checker(p_ok, p_check);
334
335                    CellLock<GridReadGuard> cell_lock(cell, p);
336
337                    TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker);
338                    cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
339                    ok = p_ok;
340                }
341
342                if (ok)
343                {
344                    //Unit *caster =  owner ? owner : ok;
345
346                    //caster->CastSpell(ok, goInfo->trap.spellId, true);
347                    CastSpell(ok, goInfo->trap.spellId);
348                    m_cooldownTime = time(NULL) + 4;        // 4 seconds
349
350                    if(NeedDespawn)
351                        SetLootState(GO_JUST_DEACTIVATED);  // can be despawned or destroyed
352
353                    if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER)
354                    {
355                        //BattleGround gameobjects case
356                        if(((Player*)ok)->InBattleGround())
357                            if(BattleGround *bg = ((Player*)ok)->GetBattleGround())
358                                bg->HandleTriggerBuff(GetGUID());
359                    }
360                }
361            }
362
363            if (m_charges && m_usetimes >= m_charges)
364                SetLootState(GO_JUST_DEACTIVATED);          // can be despawned or destroyed
365
366            break;
367        }
368        case GO_ACTIVATED:
369        {
370            switch(GetGoType())
371            {
372                case GAMEOBJECT_TYPE_DOOR:
373                case GAMEOBJECT_TYPE_BUTTON:
374                    if(GetAutoCloseTime() && (m_cooldownTime < time(NULL)))
375                    {
376                        SwitchDoorOrButton(false);
377                        SetLootState(GO_JUST_DEACTIVATED);
378                    }
379                    break;
380            }
381            break;
382        }
383        case GO_JUST_DEACTIVATED:
384        {
385            //if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed
386            if (GetGoType() == GAMEOBJECT_TYPE_GOOBER)
387            {
388                uint32 spellId = GetGOInfo()->goober.spellId;
389
390                if(spellId)
391                {
392                    std::set<uint32>::iterator it = m_unique_users.begin();
393                    std::set<uint32>::iterator end = m_unique_users.end();
394                    for (; it != end; it++)
395                    {
396                        Unit* owner = Unit::GetUnit(*this, uint64(*it));
397                        if (owner) owner->CastSpell(owner, spellId, false);
398                    }
399
400                    m_unique_users.clear();
401                    m_usetimes = 0;
402                }
403                //any return here in case battleground traps
404            }
405
406            if(GetOwnerGUID())
407            {
408                m_respawnTime = 0;
409                Delete();
410                return;
411            }
412
413            //burning flags in some battlegrounds, if you find better condition, just add it
414            if (GetGoAnimProgress() > 0)
415            {
416                SendObjectDeSpawnAnim(this->GetGUID());
417                //reset flags
418                SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags);
419            }
420
421            loot.clear();
422            SetLootState(GO_READY);
423
424            if(!m_respawnDelayTime)
425                return;
426
427            if(!m_spawnedByDefault)
428            {
429                m_respawnTime = 0;
430                return;
431            }
432
433            m_respawnTime = time(NULL) + m_respawnDelayTime;
434
435            // if option not set then object will be saved at grid unload
436            if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY))
437                SaveRespawnTime();
438
439            ObjectAccessor::UpdateObjectVisibility(this);
440
441            break;
442        }
443    }
444}
445
446void GameObject::Refresh()
447{
448    // not refresh despawned not casted GO (despawned casted GO destroyed in all cases anyway)
449    if(m_respawnTime > 0 && m_spawnedByDefault)
450        return;
451
452    if(isSpawned())
453        MapManager::Instance().GetMap(GetMapId(), this)->Add(this);
454}
455
456void GameObject::AddUniqueUse(Player* player)
457{
458    AddUse();
459    m_unique_users.insert(player->GetGUIDLow());
460}
461
462void GameObject::Delete()
463{
464    SendObjectDeSpawnAnim(GetGUID());
465
466    SetGoState(1);
467    SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags);
468
469    AddObjectToRemoveList();
470}
471
472void GameObject::getFishLoot(Loot *fishloot)
473{
474    fishloot->clear();
475
476    uint32 subzone = GetAreaId();
477
478    // if subzone loot exist use it
479    if(LootTemplates_Fishing.HaveLootFor(subzone))
480        fishloot->FillLoot(subzone, LootTemplates_Fishing, NULL);
481    // else use zone loot
482    else
483        fishloot->FillLoot(GetZoneId(), LootTemplates_Fishing, NULL);
484}
485
486void GameObject::SaveToDB()
487{
488    // this should only be used when the gameobject has already been loaded
489    // perferably after adding to map, because mapid may not be valid otherwise
490    GameObjectData const *data = objmgr.GetGOData(m_DBTableGuid);
491    if(!data)
492    {
493        sLog.outError("GameObject::SaveToDB failed, cannot get gameobject data!");
494        return;
495    }
496
497    SaveToDB(GetMapId(), data->spawnMask);
498}
499
500void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask)
501{
502    const GameObjectInfo *goI = GetGOInfo();
503
504    if (!goI)
505        return;
506   
507    if (!m_DBTableGuid)
508        m_DBTableGuid = GetGUIDLow();
509    // update in loaded data (changing data only in this place)
510    GameObjectData& data = objmgr.NewGOData(m_DBTableGuid);
511
512    // data->guid = guid don't must be update at save
513    data.id = GetEntry();
514    data.mapid = mapid;
515    data.posX = GetFloatValue(GAMEOBJECT_POS_X);
516    data.posY = GetFloatValue(GAMEOBJECT_POS_Y);
517    data.posZ = GetFloatValue(GAMEOBJECT_POS_Z);
518    data.orientation = GetFloatValue(GAMEOBJECT_FACING);
519    data.rotation0 = GetFloatValue(GAMEOBJECT_ROTATION+0);
520    data.rotation1 = GetFloatValue(GAMEOBJECT_ROTATION+1);
521    data.rotation2 = GetFloatValue(GAMEOBJECT_ROTATION+2);
522    data.rotation3 = GetFloatValue(GAMEOBJECT_ROTATION+3);
523    data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
524    data.animprogress = GetGoAnimProgress();
525    data.go_state = GetGoState();
526    data.spawnMask = spawnMask;
527    data.ArtKit = GetUInt32Value (GAMEOBJECT_ARTKIT);
528
529    // updated in DB
530    std::ostringstream ss;
531    ss << "INSERT INTO gameobject VALUES ( "
532        << m_DBTableGuid << ", "
533        << GetUInt32Value (OBJECT_FIELD_ENTRY) << ", "
534        << mapid << ", "
535        << (uint32)spawnMask << ", "
536        << GetFloatValue(GAMEOBJECT_POS_X) << ", "
537        << GetFloatValue(GAMEOBJECT_POS_Y) << ", "
538        << GetFloatValue(GAMEOBJECT_POS_Z) << ", "
539        << GetFloatValue(GAMEOBJECT_FACING) << ", "
540        << GetFloatValue(GAMEOBJECT_ROTATION) << ", "
541        << GetFloatValue(GAMEOBJECT_ROTATION+1) << ", "
542        << GetFloatValue(GAMEOBJECT_ROTATION+2) << ", "
543        << GetFloatValue(GAMEOBJECT_ROTATION+3) << ", "
544        << m_respawnDelayTime << ", "
545        << GetGoAnimProgress() << ", "
546        << GetGoState() << ")";
547
548    WorldDatabase.BeginTransaction();
549    WorldDatabase.PExecuteLog("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid);
550    WorldDatabase.PExecuteLog( ss.str( ).c_str( ) );
551    WorldDatabase.CommitTransaction();
552}
553
554bool GameObject::LoadFromDB(uint32 guid, Map *map)
555{
556    GameObjectData const* data = objmgr.GetGOData(guid);
557
558    if( !data )
559    {
560        sLog.outErrorDb("ERROR: Gameobject (GUID: %u) not found in table `gameobject`, can't load. ",guid);
561        return false;
562    }
563
564    uint32 entry = data->id;
565    uint32 map_id = data->mapid;
566    float x = data->posX;
567    float y = data->posY;
568    float z = data->posZ;
569    float ang = data->orientation;
570
571    float rotation0 = data->rotation0;
572    float rotation1 = data->rotation1;
573    float rotation2 = data->rotation2;
574    float rotation3 = data->rotation3;
575
576    uint32 animprogress = data->animprogress;
577    uint32 go_state = data->go_state;
578    uint32 ArtKit = data->ArtKit;
579
580    m_DBTableGuid = guid;
581    if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
582
583    if (!Create(guid,entry, map, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, ArtKit) )
584        return false;
585
586    switch(GetGOInfo()->type)
587    {
588        case GAMEOBJECT_TYPE_DOOR:
589        case GAMEOBJECT_TYPE_BUTTON:
590            /* this code (in comment) isn't correct because in battlegrounds we need despawnable doors and buttons, pls remove
591            SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN);
592            m_spawnedByDefault = true;
593            m_respawnDelayTime = 0;
594            m_respawnTime = 0;
595            break;*/
596        default:
597            if(data->spawntimesecs >= 0)
598            {
599                m_spawnedByDefault = true;
600                m_respawnDelayTime = data->spawntimesecs;
601                m_respawnTime = objmgr.GetGORespawnTime(m_DBTableGuid, map->GetInstanceId());
602
603                                                            // ready to respawn
604                if(m_respawnTime && m_respawnTime <= time(NULL))
605                {
606                    m_respawnTime = 0;
607                    objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0);
608                }
609            }
610            else
611            {
612                m_spawnedByDefault = false;
613                m_respawnDelayTime = -data->spawntimesecs;
614                m_respawnTime = 0;
615            }
616            break;
617    }
618
619    return true;
620}
621
622void GameObject::DeleteFromDB()
623{
624    objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0);
625    objmgr.DeleteGOData(m_DBTableGuid);
626    WorldDatabase.PExecuteLog("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid);
627    WorldDatabase.PExecuteLog("DELETE FROM game_event_gameobject WHERE guid = '%u'", m_DBTableGuid);
628}
629
630GameObject* GameObject::GetGameObject(WorldObject& object, uint64 guid)
631{
632    return ObjectAccessor::GetGameObject(object,guid);
633}
634
635GameObjectInfo const *GameObject::GetGOInfo() const
636{
637    return m_goInfo;
638}
639
640uint32 GameObject::GetLootId(GameObjectInfo const* ginfo)
641{
642    if (!ginfo)
643        return 0;
644
645    switch(ginfo->type)
646    {
647        case GAMEOBJECT_TYPE_CHEST:
648            return ginfo->chest.lootId;
649        case GAMEOBJECT_TYPE_FISHINGHOLE:
650            return ginfo->fishinghole.lootId;
651        case GAMEOBJECT_TYPE_FISHINGNODE:
652            return ginfo->fishnode.lootId;
653        default:
654            return 0;
655    }
656}
657
658/*********************************************************/
659/***                    QUEST SYSTEM                   ***/
660/*********************************************************/
661bool GameObject::hasQuest(uint32 quest_id) const
662{
663    QuestRelations const& qr = objmgr.mGOQuestRelations;
664    for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr)
665    {
666        if(itr->second==quest_id)
667            return true;
668    }
669    return false;
670}
671
672bool GameObject::hasInvolvedQuest(uint32 quest_id) const
673{
674    QuestRelations const& qr = objmgr.mGOQuestInvolvedRelations;
675    for(QuestRelations::const_iterator itr = qr.lower_bound(GetEntry()); itr != qr.upper_bound(GetEntry()); ++itr)
676    {
677        if(itr->second==quest_id)
678            return true;
679    }
680    return false;
681}
682
683bool GameObject::IsTransport() const
684{
685    // If something is marked as a transport, don't transmit an out of range packet for it.
686    GameObjectInfo const * gInfo = GetGOInfo();
687    if(!gInfo) return false;
688    return gInfo->type == GAMEOBJECT_TYPE_TRANSPORT || gInfo->type == GAMEOBJECT_TYPE_MO_TRANSPORT;
689}
690
691Unit* GameObject::GetOwner() const
692{
693    return ObjectAccessor::GetUnit(*this, GetOwnerGUID());
694}
695
696void GameObject::SaveRespawnTime()
697{
698    if(m_respawnTime > time(NULL) && m_spawnedByDefault)
699        objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime);
700}
701
702bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const
703{
704    // Not in world
705    if(!IsInWorld() || !u->IsInWorld())
706        return false;
707
708    // Transport always visible at this step implementation
709    if(IsTransport() && IsInMap(u))
710        return true;
711
712    // quick check visibility false cases for non-GM-mode
713    if(!u->isGameMaster())
714    {
715        // despawned and then not visible for non-GM in GM-mode
716        if(!isSpawned())
717            return false;
718
719        // special invisibility cases
720        /* TODO: implement trap stealth, take look at spell 2836
721        if(GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && GetGOInfo()->trap.stealthed && u->IsHostileTo(GetOwner()))
722        {
723            if(check stuff here)
724                return false;
725        }*/
726
727        // Smuggled Mana Cell required 10 invisibility type detection/state
728        if(GetEntry()==187039 && ((u->m_detectInvisibilityMask | u->m_invisibilityMask) & (1<<10))==0)
729            return false;
730    }
731
732    // check distance
733    return IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject() +
734        (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f) );
735}
736
737void GameObject::Respawn()
738{
739    if(m_spawnedByDefault && m_respawnTime > 0)
740    {
741        m_respawnTime = time(NULL);
742        objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),0);
743    }
744}
745
746bool GameObject::ActivateToQuest( Player *pTarget)const
747{
748    if(!objmgr.IsGameObjectForQuests(GetEntry()))
749        return false;
750
751    switch(GetGoType())
752    {
753        // scan GO chest with loot including quest items
754        case GAMEOBJECT_TYPE_CHEST:
755        {
756            if(LootTemplates_Gameobject.HaveQuestLootForPlayer(GetLootId(), pTarget))
757                return true;
758            break;
759        }
760        case GAMEOBJECT_TYPE_GOOBER:
761        {
762            if(pTarget->GetQuestStatus(GetGOInfo()->goober.questId) == QUEST_STATUS_INCOMPLETE)
763                return true;
764            break;
765        }
766        default:
767            break;
768    }
769
770    return false;
771}
772
773void GameObject::TriggeringLinkedGameObject( uint32 trapEntry, Unit* target)
774{
775    GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(trapEntry);
776    if(!trapInfo || trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
777        return;
778
779    SpellEntry const* trapSpell = sSpellStore.LookupEntry(trapInfo->trap.spellId);
780    if(!trapSpell)                                          // checked at load already
781        return;
782
783    float range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(trapSpell->rangeIndex));
784
785    // search nearest linked GO
786    GameObject* trapGO = NULL;
787    {
788        // using original GO distance
789        CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
790        Cell cell(p);
791        cell.data.Part.reserved = ALL_DISTRICT;
792
793        Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*target,trapEntry,range);
794        Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(trapGO,go_check);
795
796        TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);
797        CellLock<GridReadGuard> cell_lock(cell, p);
798        cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
799    }
800
801    // found correct GO
802    // FIXME: when GO casting will be implemented trap must cast spell to target
803    if(trapGO)
804        target->CastSpell(target,trapSpell,true);
805}
806
807GameObject* GameObject::LookupFishingHoleAround(float range)
808{
809    GameObject* ok = NULL;
810
811    CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY()));
812    Cell cell(p);
813    cell.data.Part.reserved = ALL_DISTRICT;
814    Trinity::NearestGameObjectFishingHole u_check(*this, range);
815    Trinity::GameObjectSearcher<Trinity::NearestGameObjectFishingHole> checker(ok, u_check);
816
817    CellLock<GridReadGuard> cell_lock(cell, p);
818
819    TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::NearestGameObjectFishingHole>, GridTypeMapContainer > grid_object_checker(checker);
820    cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this));
821
822    return ok;
823}
824
825void GameObject::UseDoorOrButton(uint32 time_to_restore)
826{
827    if(m_lootState != GO_READY)
828        return;
829
830    if(!time_to_restore)
831        time_to_restore = GetAutoCloseTime();
832
833    SwitchDoorOrButton(true);
834    SetLootState(GO_ACTIVATED);
835
836    m_cooldownTime = time(NULL) + time_to_restore;
837
838}
839
840void GameObject::SetGoArtKit(uint32 kit)
841{
842    SetUInt32Value(GAMEOBJECT_ARTKIT, kit);
843    GameObjectData *data = const_cast<GameObjectData*>(objmgr.GetGOData(m_DBTableGuid));
844    if(data)
845        data->ArtKit = kit;
846}
847
848void GameObject::SwitchDoorOrButton(bool activate)
849{
850    if(activate)
851        SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
852    else
853        RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
854
855    if(GetGoState())                                        //if closed -> open
856        SetGoState(0);
857    else                                                    //if open -> close
858        SetGoState(1);
859}
860
861void GameObject::Use(Unit* user)
862{
863    // by default spell caster is user
864    Unit* spellCaster = user;
865    uint32 spellId = 0;
866
867    switch(GetGoType())
868    {
869        case GAMEOBJECT_TYPE_DOOR:                          //0
870        case GAMEOBJECT_TYPE_BUTTON:                        //1
871            //doors/buttons never really despawn, only reset to default state/flags
872            UseDoorOrButton();
873
874            // activate script
875            sWorld.ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this);
876            return;
877
878        case GAMEOBJECT_TYPE_QUESTGIVER:                    //2
879        {
880            if(user->GetTypeId()!=TYPEID_PLAYER)
881                return;
882
883            Player* player = (Player*)user;
884
885            player->PrepareQuestMenu( GetGUID() );
886            player->SendPreparedQuest( GetGUID() );
887            return;
888        }
889        //Sitting: Wooden bench, chairs enzz
890        case GAMEOBJECT_TYPE_CHAIR:                         //7
891        {
892            GameObjectInfo const* info = GetGOInfo();
893            if(!info)
894                return;
895
896            if(user->GetTypeId()!=TYPEID_PLAYER)
897                return;
898
899            Player* player = (Player*)user;
900
901            // a chair may have n slots. we have to calculate their positions and teleport the player to the nearest one
902
903            // check if the db is sane
904            if(info->chair.slots > 0)
905            {
906                float lowestDist = DEFAULT_VISIBILITY_DISTANCE;
907
908                float x_lowest = GetPositionX();
909                float y_lowest = GetPositionY();
910
911                // the object orientation + 1/2 pi
912                // every slot will be on that straight line
913                float orthogonalOrientation = GetOrientation()+M_PI*0.5f;
914                // find nearest slot
915                for(uint32 i=0; i<info->chair.slots; i++)
916                {
917                    // the distance between this slot and the center of the go - imagine a 1D space
918                    float relativeDistance = (info->size*i)-(info->size*(info->chair.slots-1)/2.0f);
919
920                    float x_i = GetPositionX() + relativeDistance * cos(orthogonalOrientation);
921                    float y_i = GetPositionY() + relativeDistance * sin(orthogonalOrientation);
922
923                    // calculate the distance between the player and this slot
924                    float thisDistance = player->GetDistance2d(x_i, y_i);
925
926                    /* debug code. It will spawn a npc on each slot to visualize them.
927                    Creature* helper = player->SummonCreature(14496, x_i, y_i, GetPositionZ(), GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 10000);
928                    std::ostringstream output;
929                    output << i << ": thisDist: " << thisDistance;
930                    helper->MonsterSay(output.str().c_str(), LANG_UNIVERSAL, 0);
931                    */
932
933                    if(thisDistance <= lowestDist)
934                    {
935                        lowestDist = thisDistance;
936                        x_lowest = x_i;
937                        y_lowest = y_i;
938                    }
939                }
940                player->TeleportTo(GetMapId(), x_lowest, y_lowest, GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET);
941            }
942            else
943            {
944                // fallback, will always work
945                player->TeleportTo(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET);
946            }
947            player->SetStandState(PLAYER_STATE_SIT_LOW_CHAIR+info->chair.height);
948            return;
949        }
950        //big gun, its a spell/aura
951        case GAMEOBJECT_TYPE_GOOBER:                        //10
952        {
953            GameObjectInfo const* info = GetGOInfo();
954
955            if(user->GetTypeId()==TYPEID_PLAYER)
956            {
957                Player* player = (Player*)user;
958
959                // show page
960                if(info->goober.pageId)
961                {
962                    WorldPacket data(SMSG_GAMEOBJECT_PAGETEXT, 8);
963                    data << GetGUID();
964                    player->GetSession()->SendPacket(&data);
965                }
966
967                // possible quest objective for active quests
968                player->CastedCreatureOrGO(info->id, GetGUID(), 0);
969            }
970
971            // cast this spell later if provided
972            spellId = info->goober.spellId;
973
974            break;
975        }
976        case GAMEOBJECT_TYPE_CAMERA:                        //13
977        {
978            GameObjectInfo const* info = GetGOInfo();
979            if(!info)
980                return;
981
982            if(user->GetTypeId()!=TYPEID_PLAYER)
983                return;
984
985            Player* player = (Player*)user;
986
987            if(info->camera.cinematicId)
988            {
989                WorldPacket data(SMSG_TRIGGER_CINEMATIC, 4);
990                data << info->camera.cinematicId;
991                player->GetSession()->SendPacket(&data);
992            }
993            return;
994        }
995        //fishing bobber
996        case GAMEOBJECT_TYPE_FISHINGNODE:                   //17
997        {
998            if(user->GetTypeId()!=TYPEID_PLAYER)
999                return;
1000
1001            Player* player = (Player*)user;
1002
1003            if(player->GetGUID() != GetOwnerGUID())
1004                return;
1005
1006            switch(getLootState())
1007            {
1008                case GO_READY:                              // ready for loot
1009                {
1010                    // 1) skill must be >= base_zone_skill
1011                    // 2) if skill == base_zone_skill => 5% chance
1012                    // 3) chance is linear dependence from (base_zone_skill-skill)
1013
1014                    uint32 subzone = GetAreaId();
1015
1016                    int32 zone_skill = objmgr.GetFishingBaseSkillLevel( subzone );
1017                    if(!zone_skill)
1018                        zone_skill = objmgr.GetFishingBaseSkillLevel( GetZoneId() );
1019
1020                    //provide error, no fishable zone or area should be 0
1021                    if(!zone_skill)
1022                        sLog.outErrorDb("Fishable areaId %u are not properly defined in `skill_fishing_base_level`.",subzone);
1023
1024                    int32 skill = player->GetSkillValue(SKILL_FISHING);
1025                    int32 chance = skill - zone_skill + 5;
1026                    int32 roll = irand(1,100);
1027
1028                    DEBUG_LOG("Fishing check (skill: %i zone min skill: %i chance %i roll: %i",skill,zone_skill,chance,roll);
1029
1030                    if(skill >= zone_skill && chance >= roll)
1031                    {
1032                        // prevent removing GO at spell cancel
1033                        player->RemoveGameObject(this,false);
1034                        SetOwnerGUID(player->GetGUID());
1035
1036                        //fish catched
1037                        player->UpdateFishingSkill();
1038
1039                        GameObject* ok = LookupFishingHoleAround(DEFAULT_VISIBILITY_DISTANCE);
1040                        if (ok)
1041                        {
1042                            player->SendLoot(ok->GetGUID(),LOOT_FISHINGHOLE);
1043                            SetLootState(GO_JUST_DEACTIVATED);
1044                        }
1045                        else
1046                            player->SendLoot(GetGUID(),LOOT_FISHING);
1047                    }
1048                    else
1049                    {
1050                        // fish escaped, can be deleted now
1051                        SetLootState(GO_JUST_DEACTIVATED);
1052
1053                        WorldPacket data(SMSG_FISH_ESCAPED, 0);
1054                        player->GetSession()->SendPacket(&data);
1055                    }
1056                    break;
1057                }
1058                case GO_JUST_DEACTIVATED:                   // nothing to do, will be deleted at next update
1059                    break;
1060                default:
1061                {
1062                    SetLootState(GO_JUST_DEACTIVATED);
1063
1064                    WorldPacket data(SMSG_FISH_NOT_HOOKED, 0);
1065                    player->GetSession()->SendPacket(&data);
1066                    break;
1067                }
1068            }
1069
1070            if(player->m_currentSpells[CURRENT_CHANNELED_SPELL])
1071            {
1072                player->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
1073                player->m_currentSpells[CURRENT_CHANNELED_SPELL]->finish();
1074            }
1075            return;
1076        }
1077
1078        case GAMEOBJECT_TYPE_SUMMONING_RITUAL:              //18
1079        {
1080            if(user->GetTypeId()!=TYPEID_PLAYER)
1081                return;
1082
1083            Player* player = (Player*)user;
1084
1085            Unit* caster = GetOwner();
1086
1087            GameObjectInfo const* info = GetGOInfo();
1088
1089            if( !caster || caster->GetTypeId()!=TYPEID_PLAYER )
1090                return;
1091
1092            // accept only use by player from same group for caster except caster itself
1093            if(((Player*)caster)==player || !((Player*)caster)->IsInSameRaidWith(player))
1094                return;
1095
1096            AddUniqueUse(player);
1097
1098            // full amount unique participants including original summoner
1099            if(GetUniqueUseCount() < info->summoningRitual.reqParticipants)
1100                return;
1101
1102            // in case summoning ritual caster is GO creator
1103            spellCaster = caster;
1104
1105            if(!caster->m_currentSpells[CURRENT_CHANNELED_SPELL])
1106                return;
1107
1108            spellId = info->summoningRitual.spellId;
1109
1110            // finish spell
1111            caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
1112            caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->finish();
1113
1114            // can be deleted now
1115            SetLootState(GO_JUST_DEACTIVATED);
1116
1117            // go to end function to spell casting
1118            break;
1119        }
1120        case GAMEOBJECT_TYPE_SPELLCASTER:                   //22
1121        {
1122            SetUInt32Value(GAMEOBJECT_FLAGS,2);
1123
1124            GameObjectInfo const* info = GetGOInfo();
1125            if(!info)
1126                return;
1127
1128            if(info->spellcaster.partyOnly)
1129            {
1130                Unit* caster = GetOwner();
1131                if( !caster || caster->GetTypeId()!=TYPEID_PLAYER )
1132                    return;
1133
1134                if(user->GetTypeId()!=TYPEID_PLAYER || !((Player*)user)->IsInSameRaidWith((Player*)caster))
1135                    return;
1136            }
1137
1138            spellId = info->spellcaster.spellId;
1139
1140            AddUse();
1141            break;
1142        }
1143        case GAMEOBJECT_TYPE_MEETINGSTONE:                  //23
1144        {
1145            GameObjectInfo const* info = GetGOInfo();
1146
1147            if(user->GetTypeId()!=TYPEID_PLAYER)
1148                return;
1149
1150            Player* player = (Player*)user;
1151
1152            Player* targetPlayer = ObjectAccessor::FindPlayer(player->GetSelection());
1153
1154            // accept only use by player from same group for caster except caster itself
1155            if(!targetPlayer || targetPlayer == player || !targetPlayer->IsInSameGroupWith(player))
1156                return;
1157
1158            //required lvl checks!
1159            uint8 level = player->getLevel();
1160            if (level < info->meetingstone.minLevel || level > info->meetingstone.maxLevel)
1161                return;
1162            level = targetPlayer->getLevel();
1163            if (level < info->meetingstone.minLevel || level > info->meetingstone.maxLevel)
1164                return;
1165
1166            spellId = 23598;
1167
1168            break;
1169        }
1170
1171        case GAMEOBJECT_TYPE_FLAGSTAND:                     // 24
1172        {
1173            if(user->GetTypeId()!=TYPEID_PLAYER)
1174                return;
1175
1176            Player* player = (Player*)user;
1177
1178            if( player->isAllowUseBattleGroundObject() )
1179            {
1180                // in battleground check
1181                BattleGround *bg = player->GetBattleGround();
1182                if(!bg)
1183                    return;
1184                // BG flag click
1185                // AB:
1186                // 15001
1187                // 15002
1188                // 15003
1189                // 15004
1190                // 15005
1191                bg->EventPlayerClickedOnFlag(player, this);
1192                return;                                     //we don;t need to delete flag ... it is despawned!
1193            }
1194            break;
1195        }
1196        case GAMEOBJECT_TYPE_FLAGDROP:                      // 26
1197        {
1198            if(user->GetTypeId()!=TYPEID_PLAYER)
1199                return;
1200
1201            Player* player = (Player*)user;
1202
1203            if( player->isAllowUseBattleGroundObject() )     
1204            {
1205                // in battleground check
1206                BattleGround *bg = player->GetBattleGround();
1207                if(!bg)
1208                    return;
1209                // BG flag dropped
1210                // WS:
1211                // 179785 - Silverwing Flag
1212                // 179786 - Warsong Flag
1213                // EotS:
1214                // 184142 - Netherstorm Flag
1215                GameObjectInfo const* info = GetGOInfo();
1216                if(info)
1217                {
1218                    switch(info->id)
1219                    {
1220                        case 179785:                        // Silverwing Flag
1221                            // check if it's correct bg
1222                            if(bg->GetTypeID() == BATTLEGROUND_WS)
1223                                bg->EventPlayerClickedOnFlag(player, this);
1224                            break;
1225                        case 179786:                        // Warsong Flag
1226                            if(bg->GetTypeID() == BATTLEGROUND_WS)
1227                                bg->EventPlayerClickedOnFlag(player, this);
1228                            break;
1229                        case 184142:                        // Netherstorm Flag
1230                            if(bg->GetTypeID() == BATTLEGROUND_EY)
1231                                bg->EventPlayerClickedOnFlag(player, this);
1232                            break;
1233                    }
1234                }
1235                //this cause to call return, all flags must be deleted here!!
1236                spellId = 0;
1237                Delete();
1238            }
1239            break;
1240        }
1241        default:
1242            sLog.outDebug("Unknown Object Type %u", GetGoType());
1243            break;
1244    }
1245
1246    if(!spellId)
1247        return;
1248
1249    SpellEntry const *spellInfo = sSpellStore.LookupEntry( spellId );
1250    if(!spellInfo)
1251    {
1252        if(user->GetTypeId()!=TYPEID_PLAYER || !sOutdoorPvPMgr.HandleCustomSpell((Player*)user,spellId,this))
1253            sLog.outError("WORLD: unknown spell id %u at use action for gameobject (Entry: %u GoType: %u )", spellId,GetEntry(),GetGoType());
1254        else
1255            sLog.outDebug("WORLD: %u non-dbc spell was handled by OutdoorPvP", spellId);
1256        return;
1257    }
1258
1259    Spell *spell = new Spell(spellCaster, spellInfo, false);
1260
1261    // spell target is user of GO
1262    SpellCastTargets targets;
1263    targets.setUnitTarget( user );
1264
1265    spell->prepare(&targets);
1266}
1267
1268void GameObject::CastSpell(Unit* target, uint32 spell)
1269{
1270    //summon world trigger
1271    Creature *trigger = SummonCreature(12999, GetPositionX(), GetPositionY(), GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 1);
1272    if(!trigger) return;
1273
1274    trigger->SetVisibility(VISIBILITY_OFF); //should this be true?
1275    if(Unit *owner = GetOwner())
1276    {
1277        trigger->setFaction(owner->getFaction());
1278        trigger->CastSpell(target, spell, true, 0, 0, owner->GetGUID());
1279    }
1280    else
1281    {
1282        trigger->setFaction(14);
1283        trigger->CastSpell(target, spell, true);
1284    }
1285    //trigger->setDeathState(JUST_DIED);
1286    //trigger->RemoveCorpse();
1287}
Note: See TracBrowser for help on using the browser.