[7160] Implement (un-)learning skill level dependent spells at skill level change.
[getmangos.git] / src / game / ObjectAccessor.cpp
blob3ae24e1d83bede77335cc030eee20d7e39b1a76f
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
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.
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.
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
19 #include "ObjectAccessor.h"
20 #include "ObjectMgr.h"
21 #include "Policies/SingletonImp.h"
22 #include "Player.h"
23 #include "Creature.h"
24 #include "GameObject.h"
25 #include "DynamicObject.h"
26 #include "Corpse.h"
27 #include "WorldSession.h"
28 #include "WorldPacket.h"
29 #include "Item.h"
30 #include "Corpse.h"
31 #include "GridNotifiers.h"
32 #include "MapManager.h"
33 #include "Map.h"
34 #include "CellImpl.h"
35 #include "GridNotifiersImpl.h"
36 #include "Opcodes.h"
37 #include "ObjectDefines.h"
38 #include "MapInstanced.h"
39 #include "World.h"
41 #include <cmath>
43 #define CLASS_LOCK MaNGOS::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex>
44 INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
45 INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ZThread::FastMutex);
47 namespace MaNGOS
49 struct MANGOS_DLL_DECL BuildUpdateForPlayer
51 Player &i_player;
52 UpdateDataMapType &i_updatePlayers;
54 BuildUpdateForPlayer(Player &player, UpdateDataMapType &data_map) : i_player(player), i_updatePlayers(data_map) {}
56 void Visit(PlayerMapType &m)
58 for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
60 if( iter->getSource() == &i_player )
61 continue;
63 UpdateDataMapType::iterator iter2 = i_updatePlayers.find(iter->getSource());
64 if( iter2 == i_updatePlayers.end() )
66 std::pair<UpdateDataMapType::iterator, bool> p = i_updatePlayers.insert( ObjectAccessor::UpdateDataValueType(iter->getSource(), UpdateData()) );
67 assert(p.second);
68 iter2 = p.first;
71 i_player.BuildValuesUpdateBlockForPlayer(&iter2->second, iter2->first);
75 template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
79 ObjectAccessor::ObjectAccessor() {}
80 ObjectAccessor::~ObjectAccessor() {}
82 Creature*
83 ObjectAccessor::GetNPCIfCanInteractWith(Player const &player, uint64 guid, uint32 npcflagmask)
85 // unit checks
86 if (!guid)
87 return NULL;
89 // exist
90 Creature *unit = GetCreature(player, guid);
91 if (!unit)
92 return NULL;
94 // player check
95 if(!player.CanInteractWithNPCs(!unit->isSpiritService()))
96 return NULL;
98 // appropriate npc type
99 if(npcflagmask && !unit->HasFlag( UNIT_NPC_FLAGS, npcflagmask ))
100 return NULL;
102 // alive or spirit healer
103 if(!unit->isAlive() && (!unit->isSpiritService() || player.isAlive() ))
104 return NULL;
106 // not allow interaction under control
107 if(unit->GetCharmerOrOwnerGUID())
108 return NULL;
110 // not enemy
111 if( unit->IsHostileTo(&player))
112 return NULL;
114 // not unfriendly
115 FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(unit->getFaction());
116 if(factionTemplate)
118 FactionEntry const* faction = sFactionStore.LookupEntry(factionTemplate->faction);
119 if( faction->reputationListID >= 0 && player.GetReputationRank(faction) <= REP_UNFRIENDLY)
120 return NULL;
123 // not too far
124 if(!unit->IsWithinDistInMap(&player,INTERACTION_DISTANCE))
125 return NULL;
127 return unit;
130 Creature*
131 ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const &u, uint64 guid)
133 if(Creature *unit = GetPet(guid))
134 return unit;
136 if(Creature *unit = GetVehicle(guid))
137 return unit;
139 return GetCreature(u, guid);
142 Creature*
143 ObjectAccessor::GetCreature(WorldObject const &u, uint64 guid)
145 Creature * ret = GetObjectInWorld(guid, (Creature*)NULL);
146 if(!ret)
147 return NULL;
149 if(ret->GetMapId() != u.GetMapId())
150 return NULL;
152 if(ret->GetInstanceId() != u.GetInstanceId())
153 return NULL;
155 return ret;
158 Unit*
159 ObjectAccessor::GetUnit(WorldObject const &u, uint64 guid)
161 if(!guid)
162 return NULL;
164 if(IS_PLAYER_GUID(guid))
165 return FindPlayer(guid);
167 return GetCreatureOrPetOrVehicle(u, guid);
170 Corpse*
171 ObjectAccessor::GetCorpse(WorldObject const &u, uint64 guid)
173 Corpse * ret = GetObjectInWorld(guid, (Corpse*)NULL);
174 if(!ret)
175 return NULL;
176 if(ret->GetMapId() != u.GetMapId())
177 ret = NULL;
178 if(ret->GetInstanceId() != u.GetInstanceId())
179 return NULL;
180 return ret;
183 Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, uint32 typemask)
185 Object *obj = NULL;
187 if(typemask & TYPEMASK_PLAYER)
189 obj = FindPlayer(guid);
190 if(obj) return obj;
193 if(typemask & TYPEMASK_UNIT)
195 obj = GetCreatureOrPetOrVehicle(p,guid);
196 if(obj) return obj;
199 if(typemask & TYPEMASK_GAMEOBJECT)
201 obj = GetGameObject(p,guid);
202 if(obj) return obj;
205 if(typemask & TYPEMASK_DYNAMICOBJECT)
207 obj = GetDynamicObject(p,guid);
208 if(obj) return obj;
211 if(typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER)
213 obj = ((Player const &)p).GetItemByGuid( guid );
214 if(obj) return obj;
217 return NULL;
220 GameObject*
221 ObjectAccessor::GetGameObject(WorldObject const &u, uint64 guid)
223 GameObject * ret = GetObjectInWorld(guid, (GameObject*)NULL);
224 if(!ret)
225 return NULL;
226 if(ret->GetMapId() != u.GetMapId())
227 ret = NULL;
228 if(ret->GetInstanceId() != u.GetInstanceId())
229 return NULL;
230 return ret;
233 DynamicObject*
234 ObjectAccessor::GetDynamicObject(WorldObject const &u, uint64 guid)
236 DynamicObject * ret = GetObjectInWorld(guid, (DynamicObject*)NULL);
237 if(!ret)
238 return NULL;
239 if(ret->GetMapId() != u.GetMapId())
240 ret = NULL;
241 if(ret->GetInstanceId() != u.GetInstanceId())
242 return NULL;
243 return ret;
246 Player*
247 ObjectAccessor::FindPlayer(uint64 guid)
249 return GetObjectInWorld(guid, (Player*)NULL);
252 Player*
253 ObjectAccessor::FindPlayerByName(const char *name)
255 //TODO: Player Guard
256 HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
257 HashMapHolder<Player>::MapType::iterator iter = m.begin();
258 for(; iter != m.end(); ++iter)
259 if( ::strcmp(name, iter->second->GetName()) == 0 )
260 return iter->second;
261 return NULL;
264 void
265 ObjectAccessor::SaveAllPlayers()
267 Guard guard(*HashMapHolder<Player*>::GetLock());
268 HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
269 HashMapHolder<Player>::MapType::iterator itr = m.begin();
270 for(; itr != m.end(); ++itr)
271 itr->second->SaveToDB();
274 void
275 ObjectAccessor::UpdateObject(Object* obj, Player* exceptPlayer)
277 UpdateDataMapType update_players;
278 obj->BuildUpdate(update_players);
280 WorldPacket packet;
281 for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
283 if(iter->first == exceptPlayer)
284 continue;
286 iter->second.BuildPacket(&packet);
287 iter->first->GetSession()->SendPacket(&packet);
288 packet.clear();
292 void
293 ObjectAccessor::_buildUpdateObject(Object *obj, UpdateDataMapType &update_players)
295 bool build_for_all = true;
296 Player *pl = NULL;
297 if( obj->isType(TYPEMASK_ITEM) )
299 Item *item = static_cast<Item *>(obj);
300 pl = item->GetOwner();
301 build_for_all = false;
304 if( pl != NULL )
305 _buildPacket(pl, obj, update_players);
307 // Capt: okey for all those fools who think its a real fix
308 // THIS IS A TEMP FIX
309 if( build_for_all )
311 WorldObject * temp = dynamic_cast<WorldObject*>(obj);
313 //assert(dynamic_cast<WorldObject*>(obj)!=NULL);
314 if (temp)
315 _buildChangeObjectForPlayer(temp, update_players);
316 else
317 sLog.outDebug("ObjectAccessor: Ln 405 Temp bug fix");
321 void
322 ObjectAccessor::_buildPacket(Player *pl, Object *obj, UpdateDataMapType &update_players)
324 UpdateDataMapType::iterator iter = update_players.find(pl);
326 if( iter == update_players.end() )
328 std::pair<UpdateDataMapType::iterator, bool> p = update_players.insert( UpdateDataValueType(pl, UpdateData()) );
329 assert(p.second);
330 iter = p.first;
333 obj->BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
336 void
337 ObjectAccessor::_buildChangeObjectForPlayer(WorldObject *obj, UpdateDataMapType &update_players)
339 CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
340 Cell cell(p);
341 cell.data.Part.reserved = ALL_DISTRICT;
342 cell.SetNoCreate();
343 WorldObjectChangeAccumulator notifier(*obj, update_players);
344 TypeContainerVisitor<WorldObjectChangeAccumulator, WorldTypeMapContainer > player_notifier(notifier);
345 CellLock<GridReadGuard> cell_lock(cell, p);
346 cell_lock->Visit(cell_lock, player_notifier, *obj->GetMap());
349 Pet*
350 ObjectAccessor::GetPet(uint64 guid)
352 return GetObjectInWorld(guid, (Pet*)NULL);
355 Vehicle*
356 ObjectAccessor::GetVehicle(uint64 guid)
358 return GetObjectInWorld(guid, (Vehicle*)NULL);
361 Corpse*
362 ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid)
364 Guard guard(i_corpseGuard);
366 Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid);
367 if( iter == i_player2corpse.end() ) return NULL;
369 assert(iter->second->GetType() != CORPSE_BONES);
371 return iter->second;
374 void
375 ObjectAccessor::RemoveCorpse(Corpse *corpse)
377 assert(corpse && corpse->GetType() != CORPSE_BONES);
379 Guard guard(i_corpseGuard);
380 Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID());
381 if( iter == i_player2corpse.end() )
382 return;
384 // build mapid*cellid -> guid_set map
385 CellPair cell_pair = MaNGOS::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
386 uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
388 objmgr.DeleteCorpseCellData(corpse->GetMapId(),cell_id,corpse->GetOwnerGUID());
389 corpse->RemoveFromWorld();
391 i_player2corpse.erase(iter);
394 void
395 ObjectAccessor::AddCorpse(Corpse *corpse)
397 assert(corpse && corpse->GetType() != CORPSE_BONES);
399 Guard guard(i_corpseGuard);
400 assert(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end());
401 i_player2corpse[corpse->GetOwnerGUID()] = corpse;
403 // build mapid*cellid -> guid_set map
404 CellPair cell_pair = MaNGOS::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
405 uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
407 objmgr.AddCorpseCellData(corpse->GetMapId(),cell_id,corpse->GetOwnerGUID(),corpse->GetInstanceId());
410 void
411 ObjectAccessor::AddCorpsesToGrid(GridPair const& gridpair,GridType& grid,Map* map)
413 Guard guard(i_corpseGuard);
414 for(Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter)
415 if(iter->second->GetGrid()==gridpair)
417 // verify, if the corpse in our instance (add only corpses which are)
418 if (map->Instanceable())
420 if (iter->second->GetInstanceId() == map->GetInstanceId())
422 grid.AddWorldObject(iter->second,iter->second->GetGUID());
425 else
427 grid.AddWorldObject(iter->second,iter->second->GetGUID());
432 Corpse*
433 ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia)
435 Corpse *corpse = GetCorpseForPlayerGUID(player_guid);
436 if(!corpse)
438 //in fact this function is called from several places
439 //even when player doesn't have a corpse, not an error
440 //sLog.outError("ERROR: Try remove corpse that not in map for GUID %ul", player_guid);
441 return NULL;
444 DEBUG_LOG("Deleting Corpse and spawning bones.\n");
446 // remove corpse from player_guid -> corpse map
447 RemoveCorpse(corpse);
449 // remove resurrectble corpse from grid object registry (loaded state checked into call)
450 // do not load the map if it's not loaded
451 Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId());
452 if(map) map->Remove(corpse,false);
454 // remove corpse from DB
455 corpse->DeleteFromDB();
457 Corpse *bones = NULL;
458 // create the bones only if the map and the grid is loaded at the corpse's location
459 // ignore bones creating option in case insignia
460 if (map && (insignia ||
461 (map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) &&
462 !map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
464 // Create bones, don't change Corpse
465 bones = new Corpse;
466 bones->Create(corpse->GetGUIDLow());
468 for (int i = 3; i < CORPSE_END; i++) // don't overwrite guid and object type
469 bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
471 bones->SetGrid(corpse->GetGrid());
472 // bones->m_time = m_time; // don't overwrite time
473 // bones->m_inWorld = m_inWorld; // don't overwrite world state
474 // bones->m_type = m_type; // don't overwrite type
475 bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
476 bones->SetMapId(corpse->GetMapId());
477 bones->SetInstanceId(corpse->GetInstanceId());
479 bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
480 bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0);
482 for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
484 if(corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
485 bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
488 // add bones in grid store if grid loaded where corpse placed
489 map->Add(bones);
492 // all references to the corpse should be removed at this point
493 delete corpse;
495 return bones;
498 void
499 ObjectAccessor::Update(uint32 diff)
501 UpdateDataMapType update_players;
503 Guard guard(i_updateGuard);
504 while(!i_objects.empty())
506 Object* obj = *i_objects.begin();
507 i_objects.erase(i_objects.begin());
508 if (!obj)
509 continue;
510 _buildUpdateObject(obj, update_players);
511 obj->ClearUpdateMask(false);
515 WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
516 for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
518 iter->second.BuildPacket(&packet);
519 iter->first->GetSession()->SendPacket(&packet);
520 packet.clear(); // clean the string
524 void
525 ObjectAccessor::UpdatePlayers(uint32 diff)
527 HashMapHolder<Player>::MapType& playerMap = HashMapHolder<Player>::GetContainer();
528 for(HashMapHolder<Player>::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter)
529 if(iter->second->IsInWorld())
530 iter->second->Update(diff);
533 void
534 ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m)
536 for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
537 if(iter->getSource()->HaveAtClient(&i_object))
538 ObjectAccessor::_buildPacket(iter->getSource(), &i_object, i_updateDatas);
541 void
542 ObjectAccessor::UpdateObjectVisibility(WorldObject *obj)
544 CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
545 Cell cell(p);
547 obj->GetMap()->UpdateObjectVisibility(obj,cell,p);
550 void ObjectAccessor::UpdateVisibilityForPlayer( Player* player )
552 CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
553 Cell cell(p);
554 Map* m = player->GetMap();
556 m->UpdatePlayerVisibility(player,cell,p);
557 m->UpdateObjectsVisibilityFor(player,cell,p);
560 /// Define the static member of HashMapHolder
562 template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap;
563 template <class T> ZThread::FastMutex HashMapHolder<T>::i_lock;
565 /// Global definitions for the hashmap storage
567 template class HashMapHolder<Player>;
568 template class HashMapHolder<Pet>;
569 template class HashMapHolder<Vehicle>;
570 template class HashMapHolder<GameObject>;
571 template class HashMapHolder<DynamicObject>;
572 template class HashMapHolder<Creature>;
573 template class HashMapHolder<Corpse>;
575 template Player* ObjectAccessor::GetObjectInWorld<Player>(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/);
576 template Pet* ObjectAccessor::GetObjectInWorld<Pet>(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/);
577 template Vehicle* ObjectAccessor::GetObjectInWorld<Vehicle>(uint32 mapid, float x, float y, uint64 guid, Vehicle* /*fake*/);
578 template Creature* ObjectAccessor::GetObjectInWorld<Creature>(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/);
579 template Corpse* ObjectAccessor::GetObjectInWorld<Corpse>(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/);
580 template GameObject* ObjectAccessor::GetObjectInWorld<GameObject>(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/);
581 template DynamicObject* ObjectAccessor::GetObjectInWorld<DynamicObject>(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/);