diff --git a/sql/mangos.sql b/sql/mangos.sql index 26d1b3c5f..5e68dd49f 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_8676_01_mangos_creature_template` bit(1) default NULL + `required_8693_01_mangos_spell_proc_event` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -18324,6 +18324,7 @@ INSERT INTO `spell_proc_event` VALUES (63108, 0x00000000, 5, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (63156, 0x00000000, 0, 0x00000001, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (63245, 0x00000000, 5, 0x00000100, 0x00800000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0), +(63320, 0x00000000, 5, 0x00040000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (63730, 0x00000000, 6, 0x00000800, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (64928, 0x00000000, 11, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0); /*!40000 ALTER TABLE `spell_proc_event` ENABLE KEYS */; diff --git a/sql/updates/8688_01_mangos_creature_template.sql b/sql/updates/8688_01_mangos_creature_template.sql new file mode 100644 index 000000000..02540006d --- /dev/null +++ b/sql/updates/8688_01_mangos_creature_template.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_8676_01_mangos_creature_template required_8688_01_mangos_creature_template bit; + +-- reverts last update - we now have something better +UPDATE creature_template SET flags_extra = flags_extra & ~(0x200) WHERE npcflag +& (16384|32768); diff --git a/sql/updates/8693_01_mangos_spell_proc_event.sql b/sql/updates/8693_01_mangos_spell_proc_event.sql new file mode 100644 index 000000000..ab9325e6d --- /dev/null +++ b/sql/updates/8693_01_mangos_spell_proc_event.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_8688_01_mangos_creature_template required_8693_01_mangos_spell_proc_event bit; + +DELETE FROM spell_proc_event WHERE entry = 63320; +INSERT INTO spell_proc_event VALUES (63320, 0x00000000, 5, 0x00040000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0); \ No newline at end of file diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 5137ff8d4..b5a77a857 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -136,6 +136,8 @@ pkgdata_DATA = \ 8608_02_mangos_battleground_events.sql \ 8618_01_mangos_spell_proc_event.sql \ 8676_01_mangos_creature_template.sql \ + 8688_01_mangos_creature_template.sql \ + 8693_01_mangos_spell_proc_event.sql \ README ## Additional files to include when running 'make dist' @@ -252,4 +254,6 @@ EXTRA_DIST = \ 8608_02_mangos_battleground_events.sql \ 8618_01_mangos_spell_proc_event.sql \ 8676_01_mangos_creature_template.sql \ + 8688_01_mangos_creature_template.sql \ + 8693_01_mangos_spell_proc_event.sql \ README diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index faa4e608d..fdde05f7d 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -19,6 +19,7 @@ #include "AggressorAI.h" #include "Errors.h" #include "Creature.h" +#include "SharedDefines.h" #include "ObjectAccessor.h" #include "VMapFactory.h" #include "World.h" @@ -46,9 +47,9 @@ AggressorAI::MoveInLineOfSight(Unit *u) if( !m_creature->canFly() && m_creature->GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE ) return; - if( !(m_creature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GHOST) && !m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED) && u->isTargetableForAttack() && + if (!m_creature->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_DIED) && u->isTargetableForAttack() && ( m_creature->IsHostileTo( u ) /*|| u->getVictim() && m_creature->IsFriendlyTo( u->getVictim() )*/ ) && - u->isInAccessablePlaceFor(m_creature) ) + u->isInAccessablePlaceFor(m_creature)) { float attackRadius = m_creature->GetAttackDistance(u); if(m_creature->IsWithinDistInMap(u, attackRadius) && m_creature->IsWithinLOSInMap(u) ) diff --git a/src/game/BattleGroundAV.cpp b/src/game/BattleGroundAV.cpp index d66da6736..e0e7f7198 100644 --- a/src/game/BattleGroundAV.cpp +++ b/src/game/BattleGroundAV.cpp @@ -336,7 +336,7 @@ void BattleGroundAV::EndBattleGround(uint32 winner) // now we have the values give the honor/reputation to the teams: uint32 team[BG_TEAMS_COUNT] = { ALLIANCE, HORDE }; uint32 faction[BG_TEAMS_COUNT] = { BG_AV_FACTION_A, BG_AV_FACTION_H }; - for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) + for (uint32 i = 0; i < BG_TEAMS_COUNT; i++) { if (tower_survived[i]) { @@ -800,6 +800,7 @@ void BattleGroundAV::Reset() m_RepOwnedGrave = (isBGWeekend) ? BG_AV_REP_OWNED_GRAVE_HOLIDAY : BG_AV_REP_OWNED_GRAVE; m_RepSurviveCaptain = (isBGWeekend) ? BG_AV_REP_SURVIVING_CAPTAIN_HOLIDAY : BG_AV_REP_SURVIVING_CAPTAIN; m_RepSurviveTower = (isBGWeekend) ? BG_AV_REP_SURVIVING_TOWER_HOLIDAY : BG_AV_REP_SURVIVING_TOWER; + m_RepOwnedMine = (isBGWeekend) ? BG_AV_REP_OWNED_MINE_HOLIDAY : BG_AV_REP_OWNED_MINE; for(uint8 i = 0; i < BG_TEAMS_COUNT; i++) { diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index b666a0289..2a195e7d0 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -1746,11 +1746,12 @@ bool Creature::IsVisibleInGridForPlayer(Player* pl) const if(pl->isGameMaster()) return true; + if (GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INVISIBLE) + return false; + // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0 if(pl->isAlive() || pl->GetDeathTimer() > 0) { - if(GetCreatureInfo()->flags_extra & (CREATURE_FLAG_EXTRA_INVISIBLE | CREATURE_FLAG_EXTRA_GHOST)) - return false; return (isAlive() || m_deathTimer > 0 || (m_isDeadByDefault && m_deathState == CORPSE)); } @@ -1766,8 +1767,8 @@ bool Creature::IsVisibleInGridForPlayer(Player* pl) const } } - // Dead player see ghosts - if (GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GHOST) + // Dead player can see ghosts + if (GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_GHOST_VISIBLE) return true; // and not see any other diff --git a/src/game/Creature.h b/src/game/Creature.h index d41364ce2..f0025a9c6 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -143,7 +143,6 @@ enum CreatureFlagsExtra CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP CREATURE_FLAG_EXTRA_INVISIBLE = 0x00000080, // creature is always invisible for player (mostly trigger creatures) CREATURE_FLAG_EXTRA_NOT_TAUNTABLE = 0x00000100, // creature is immune to taunt auras and effect attack me - CREATURE_FLAG_EXTRA_GHOST = 0x00000200, // creature is only visible for dead players }; // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h index 4291d3d77..dcb16bff8 100644 --- a/src/game/DBCEnums.h +++ b/src/game/DBCEnums.h @@ -247,6 +247,25 @@ enum Difficulty #define MAX_RAID_DIFFICULTY 4 #define MAX_DIFFICULTY 4 +enum SpawnMask +{ + SPAWNMASK_CONTINENT = 1, // any any maps without spawn modes + + SPAWNMASK_DUNGEON_NORMAL = (1 << DUNGEON_DIFFICULTY_NORMAL), + SPAWNMASK_DUNGEON_HEROIC = (1 << DUNGEON_DIFFICULTY_HEROIC), + SPAWNMASK_DUNGEON_ALL = (SPAWNMASK_DUNGEON_NORMAL | SPAWNMASK_DUNGEON_HEROIC), + + SPAWNMASK_RAID_10MAN_NORMAL = (1 << RAID_DIFFICULTY_10MAN_NORMAL), + SPAWNMASK_RAID_25MAN_NORMAL = (1 << RAID_DIFFICULTY_25MAN_NORMAL), + SPAWNMASK_RAID_NORMAL_ALL = (SPAWNMASK_RAID_10MAN_NORMAL | SPAWNMASK_RAID_25MAN_NORMAL), + + SPAWNMASK_RAID_10MAN_HEROIC = (1 << RAID_DIFFICULTY_10MAN_HEROIC), + SPAWNMASK_RAID_25MAN_HEROIC = (1 << RAID_DIFFICULTY_25MAN_HEROIC), + SPAWNMASK_RAID_HEROIC_ALL = (SPAWNMASK_RAID_10MAN_HEROIC | SPAWNMASK_RAID_25MAN_HEROIC), + + SPAWNMASK_RAID_ALL = (SPAWNMASK_RAID_NORMAL_ALL | SPAWNMASK_RAID_HEROIC_ALL), +}; + enum FactionTemplateFlags { FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h index 1340e0d1b..3db095f1e 100644 --- a/src/game/DestinationHolderImp.h +++ b/src/game/DestinationHolderImp.h @@ -21,6 +21,7 @@ #include "MapManager.h" #include "DestinationHolder.h" +#include "Unit.h" #include diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 2ff2f92c1..24f9652bd 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -522,7 +522,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) // Spawn if necessary (loaded grids only) Map* map = const_cast(MapManager::Instance().CreateBaseMap(data->mapid)); // We use spawn coords to spawn - if(!map->Instanceable() && !map->IsRemovalGrid(data->posX,data->posY)) + if(!map->Instanceable() && map->IsLoaded(data->posX,data->posY)) { Creature* pCreature = new Creature; //sLog.outDebug("Spawning creature %u",*itr); @@ -555,7 +555,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) // this base map checked as non-instanced and then only existed Map* map = const_cast(MapManager::Instance().CreateBaseMap(data->mapid)); // We use current coords to unspawn, not spawn coords since creature can have changed grid - if(!map->Instanceable() && !map->IsRemovalGrid(data->posX, data->posY)) + if(!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) { GameObject* pGameobject = new GameObject; //sLog.outDebug("Spawning gameobject %u", *itr); diff --git a/src/game/Group.cpp b/src/game/Group.cpp index b3f77f529..48aa5ec3d 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -1596,7 +1596,7 @@ InstanceGroupBind* Group::GetBoundInstance(Player* player) InstanceGroupBind* Group::GetBoundInstance(Map* aMap) { // Currently spawn numbering not different from map difficulty - Difficulty difficulty = Difficulty(aMap->GetSpawnMode()); + Difficulty difficulty = GetDifficulty(aMap->IsRaid()); // some instances only have one difficulty MapDifficulty const* mapDiff = GetMapDifficultyData(aMap->GetId(),difficulty); diff --git a/src/game/Item.cpp b/src/game/Item.cpp index 644c13dfa..ba6381cb7 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -996,6 +996,18 @@ bool Item::IsBindedNotWith( Player const* player ) const } } +void Item::AddToClientUpdateList() +{ + if (Player* pl = GetOwner()) + pl->GetMap()->AddUpdateObject(this); +} + +void Item::RemoveFromClientUpdateList() +{ + if (Player* pl = GetOwner()) + pl->GetMap()->RemoveUpdateObject(this); +} + void Item::BuildUpdateData(UpdateDataMapType& update_players) { if (Player* pl = GetOwner()) diff --git a/src/game/Item.h b/src/game/Item.h index a1b444007..59aa86f6d 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -313,6 +313,8 @@ class MANGOS_DLL_SPEC Item : public Object bool IsPotion() const { return GetProto()->IsPotion(); } bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); } + void AddToClientUpdateList(); + void RemoveFromClientUpdateList(); void BuildUpdateData(UpdateDataMapType& update_players); private: uint8 m_slot; diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 4abed7b57..51d9cddb8 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -697,6 +697,9 @@ void Map::Update(const uint32 &t_diff) } } + // Send world objects and item update field changes + SendObjectUpdates(); + // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended if (!IsBattleGroundOrArena()) @@ -3415,3 +3418,25 @@ DynamicObject* Map::GetDynamicObject(uint64 guid) { return m_objectsStore.find(guid, (DynamicObject*)NULL); } + +void Map::SendObjectUpdates() +{ + UpdateDataMapType update_players; + + while(!i_objectsToClientUpdate.empty()) + { + Object* obj = *i_objectsToClientUpdate.begin(); + i_objectsToClientUpdate.erase(i_objectsToClientUpdate.begin()); + if (!obj) + continue; + obj->BuildUpdateData(update_players); + } + + WorldPacket packet; // here we allocate a std::vector with a size of 0x10000 + for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) + { + iter->second.BuildPacket(&packet); + iter->first->GetSession()->SendPacket(&packet); + packet.clear(); // clean the string + } +} \ No newline at end of file diff --git a/src/game/Map.h b/src/game/Map.h index a50a3e1f4..1a458bda8 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -296,6 +296,12 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj return( !getNGrid(p.x_coord, p.y_coord) || getNGrid(p.x_coord, p.y_coord)->GetGridState() == GRID_STATE_REMOVAL ); } + bool IsLoaded(float x, float y) const + { + GridPair p = MaNGOS::ComputeGridPair(x, y); + return loaded(p); + } + bool GetUnloadLock(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadLock(); } void SetUnloadLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadExplicitLock(on); } void LoadGrid(const Cell& cell, bool no_unload = false); @@ -428,6 +434,16 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj DynamicObject* GetDynamicObject(uint64 guid); TypeUnorderedMapContainer& GetObjectsStore() { return m_objectsStore; } + + void AddUpdateObject(Object *obj) + { + i_objectsToClientUpdate.insert(obj); + } + + void RemoveUpdateObject(Object *obj) + { + i_objectsToClientUpdate.erase( obj ); + } private: void LoadMapAndVMap(int gx, int gy); void LoadVMap(int gx, int gy); @@ -472,6 +488,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void setNGrid(NGridType* grid, uint32 x, uint32 y); void ScriptsProcess(); + void SendObjectUpdates(); + std::set i_objectsToClientUpdate; protected: void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp index 0aa985ffe..1455adf7e 100644 --- a/src/game/MapInstanced.cpp +++ b/src/game/MapInstanced.cpp @@ -167,7 +167,9 @@ Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) // if no instanceId via group members or instance saves is found // the instance will be created for the first time NewInstanceId = MapManager::Instance().GenerateInstanceId(); - map = CreateInstance(NewInstanceId, NULL, player->GetDifficulty(IsRaid())); + + Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(IsRaid()) : player->GetDifficulty(IsRaid()); + map = CreateInstance(NewInstanceId, NULL, diff); } } diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 624e3b884..65157aedd 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -21,7 +21,6 @@ #include "Policies/SingletonImp.h" #include "Database/DatabaseEnv.h" #include "Log.h" -#include "ObjectAccessor.h" #include "Transports.h" #include "GridDefines.h" #include "MapInstanced.h" @@ -268,7 +267,6 @@ MapManager::Update(uint32 diff) iter->second->Update(i_timer.GetCurrent()); } - ObjectAccessor::Instance().Update(i_timer.GetCurrent()); for (TransportSet::iterator iter = m_Transports.begin(); iter != m_Transports.end(); ++iter) (*iter)->Update(i_timer.GetCurrent()); diff --git a/src/game/Object.cpp b/src/game/Object.cpp index bf090d523..ea14e7545 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -31,7 +31,6 @@ #include "UpdateMask.h" #include "Util.h" #include "MapManager.h" -#include "ObjectAccessor.h" #include "Log.h" #include "Transports.h" #include "TargetedMovementGenerator.h" @@ -80,9 +79,6 @@ Object::Object( ) : m_PackGUID(sizeof(uint64)+1) Object::~Object( ) { - if(m_objectUpdated) - ObjectAccessor::Instance().RemoveUpdateObject(this); - if(m_uint32Values) { if(IsInWorld()) @@ -744,10 +740,11 @@ void Object::ClearUpdateMask(bool remove) if(m_uint32Values_mirror[index]!= m_uint32Values[index]) m_uint32Values_mirror[index] = m_uint32Values[index]; } + if(m_objectUpdated) { if(remove) - ObjectAccessor::Instance().RemoveUpdateObject(this); + RemoveFromClientUpdateList(); m_objectUpdated = false; } } @@ -801,7 +798,7 @@ void Object::SetInt32Value( uint16 index, int32 value ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -820,7 +817,7 @@ void Object::SetUInt32Value( uint16 index, uint32 value ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -839,7 +836,7 @@ void Object::SetUInt64Value( uint16 index, const uint64 &value ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -858,7 +855,7 @@ void Object::SetFloatValue( uint16 index, float value ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -884,7 +881,7 @@ void Object::SetByteValue( uint16 index, uint8 offset, uint8 value ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -910,7 +907,7 @@ void Object::SetUInt16Value( uint16 index, uint8 offset, uint16 value ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -979,7 +976,7 @@ void Object::SetFlag( uint16 index, uint32 newFlag ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -1000,7 +997,7 @@ void Object::RemoveFlag( uint16 index, uint32 oldFlag ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -1025,7 +1022,7 @@ void Object::SetByteFlag( uint16 index, uint8 offset, uint8 newFlag ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -1050,7 +1047,7 @@ void Object::RemoveByteFlag( uint16 index, uint8 offset, uint8 oldFlag ) { if(!m_objectUpdated) { - ObjectAccessor::Instance().AddUpdateObject(this); + AddToClientUpdateList(); m_objectUpdated = true; } } @@ -1079,6 +1076,24 @@ void Object::BuildUpdateDataForPlayer(Player* pl, UpdateDataMapType& update_play BuildValuesUpdateBlockForPlayer(&iter->second, iter->first); } +void Object::AddToClientUpdateList() +{ + sLog.outError("Unexpected call of Object::AddToClientUpdateList for object (TypeId: %u Update fields: %u)",GetTypeId(), m_valuesCount); + ASSERT(false); +} + +void Object::RemoveFromClientUpdateList() +{ + sLog.outError("Unexpected call of Object::RemoveFromClientUpdateList for object (TypeId: %u Update fields: %u)",GetTypeId(), m_valuesCount); + ASSERT(false); +} + +void Object::BuildUpdateData( UpdateDataMapType& update_players ) +{ + sLog.outError("Unexpected call of Object::BuildUpdateData for object (TypeId: %u Update fields: %u)",GetTypeId(), m_valuesCount); + ASSERT(false); +} + WorldObject::WorldObject() : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f), m_currMap(NULL) @@ -1871,6 +1886,16 @@ void WorldObject::UpdateObjectVisibility() GetMap()->UpdateObjectVisibility(this, cell, p); } +void WorldObject::AddToClientUpdateList() +{ + GetMap()->AddUpdateObject(this); +} + +void WorldObject::RemoveFromClientUpdateList() +{ + GetMap()->RemoveUpdateObject(this); +} + struct WorldObjectChangeAccumulator { UpdateDataMapType &i_updateDatas; diff --git a/src/game/Object.h b/src/game/Object.h index 20b543eab..67a183ad9 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -124,7 +124,7 @@ class MANGOS_DLL_SPEC Object m_inWorld = true; // synchronize values mirror with values array (changes will send in updatecreate opcode any way - ClearUpdateMask(true); + ClearUpdateMask(false); // false - we can't have update dat in update queue before adding to world } virtual void RemoveFromWorld() { @@ -148,7 +148,11 @@ class MANGOS_DLL_SPEC Object virtual void BuildCreateUpdateBlockForPlayer( UpdateData *data, Player *target ) const; void SendCreateUpdateToPlayer(Player* player); - virtual void BuildUpdateData(UpdateDataMapType& update_players) =0; + // must be overwrite in appropriate subclasses (WorldObject, Item currently), or will crash + virtual void AddToClientUpdateList(); + virtual void RemoveFromClientUpdateList(); + virtual void BuildUpdateData(UpdateDataMapType& update_players); + void BuildValuesUpdateBlockForPlayer( UpdateData *data, Player *target ) const; void BuildOutOfRangeUpdateBlock( UpdateData *data ) const; void BuildMovementUpdateBlock( UpdateData * data, uint32 flags = 0 ) const; @@ -308,6 +312,7 @@ class MANGOS_DLL_SPEC Object virtual void _SetUpdateBits(UpdateMask *updateMask, Player *target) const; virtual void _SetCreateBits(UpdateMask *updateMask, Player *target) const; + void BuildMovementUpdate(ByteBuffer * data, uint16 flags, uint32 flags2 ) const; void BuildValuesUpdate(uint8 updatetype, ByteBuffer *data, UpdateMask *updateMask, Player *target ) const; void BuildUpdateDataForPlayer(Player* pl, UpdateDataMapType& update_players); @@ -494,6 +499,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object //this function should be removed in nearest time... Map const* GetBaseMap() const; + void AddToClientUpdateList(); + void RemoveFromClientUpdateList(); void BuildUpdateData(UpdateDataMapType &); Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime); diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index dc377cd12..7cc289104 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -331,31 +331,6 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia) return bones; } -void -ObjectAccessor::Update(uint32 diff) -{ - UpdateDataMapType update_players; - { - Guard guard(i_updateGuard); - while(!i_objects.empty()) - { - Object* obj = *i_objects.begin(); - i_objects.erase(i_objects.begin()); - if (!obj) - continue; - obj->BuildUpdateData(update_players); - } - } - - WorldPacket packet; // here we allocate a std::vector with a size of 0x10000 - for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter) - { - iter->second.BuildPacket(&packet); - iter->first->GetSession()->SendPacket(&packet); - packet.clear(); // clean the string - } -} - /// Define the static member of HashMapHolder template UNORDERED_MAP< uint64, T* > HashMapHolder::m_objectMap; diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 5778732c7..c562f5e74 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -152,27 +152,10 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton::Remove(pl); - - Guard guard(i_updateGuard); - i_objects.erase((Object *)pl); } void SaveAllPlayers(); - void AddUpdateObject(Object *obj) - { - Guard guard(i_updateGuard); - i_objects.insert(obj); - } - - void RemoveUpdateObject(Object *obj) - { - Guard guard(i_updateGuard); - i_objects.erase( obj ); - } - - void Update(uint32 diff); - Corpse* GetCorpseForPlayerGUID(uint64 guid); void RemoveCorpse(Corpse *corpse); void AddCorpse(Corpse* corpse); @@ -206,9 +189,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton Guard; - std::set i_objects; LockType i_playerGuard; - LockType i_updateGuard; LockType i_corpseGuard; }; diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 22a46ae1f..d4a002855 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -1041,6 +1041,14 @@ void ObjectMgr::LoadCreatures() if(cInfo->HeroicEntry) heroicCreatures.insert(cInfo->HeroicEntry); + // build single time for check spawnmask + std::map spawnMasks; + for(uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + if(sMapStore.LookupEntry(i)) + for(int k = 0; k < MAX_DIFFICULTY; ++k) + if (GetMapDifficultyData(i,Difficulty(k))) + spawnMasks[i] |= (1 << k); + barGoLink bar(result->GetRowCount()); do @@ -1080,6 +1088,16 @@ void ObjectMgr::LoadCreatures() int16 gameEvent = fields[18].GetInt16(); int16 PoolId = fields[19].GetInt16(); + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); + if(!mapEntry) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that spawned at not existed map (Id: %u), skipped.",guid, data.mapid ); + continue; + } + + if (data.spawnMask & ~spawnMasks[data.mapid]) + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).",guid, data.spawnMask, data.mapid ); + if(heroicCreatures.find(data.id)!=heroicCreatures.end()) { sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template (entry: %u) in `creature_template`, skipped.",guid, data.id ); @@ -1103,8 +1121,7 @@ void ObjectMgr::LoadCreatures() if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) { - MapEntry const* map = sMapStore.LookupEntry(data.mapid); - if(!map || !map->IsDungeon()) + if(!mapEntry || !mapEntry->IsDungeon()) sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id); } @@ -1209,6 +1226,14 @@ void ObjectMgr::LoadGameobjects() return; } + // build single time for check spawnmask + std::map spawnMasks; + for(uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + if(sMapStore.LookupEntry(i)) + for(int k = 0; k < MAX_DIFFICULTY; ++k) + if (GetMapDifficultyData(i,Difficulty(k))) + spawnMasks[i] |= (1 << k); + barGoLink bar(result->GetRowCount()); do @@ -1259,6 +1284,16 @@ void ObjectMgr::LoadGameobjects() data.rotation3 = fields[10].GetFloat(); data.spawntimesecs = fields[11].GetInt32(); + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); + if(!mapEntry) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that spawned at not existed map (Id: %u), skip", guid, data.id, data.mapid); + continue; + } + + if (data.spawnMask & ~spawnMasks[data.mapid]) + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid); + if (data.spawntimesecs == 0 && gInfo->IsDespawnAtAction()) { sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but gameobejct marked as despawnable at action.", guid, data.id); diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index d1765c092..97bb876c3 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -1179,10 +1179,10 @@ void Pet::_LoadAuras(uint32 timediff) // negative effects should continue counting down after logout if (remaintime != -1 && !IsPositiveEffect(spellid, effindex)) { - if(remaintime <= int32(timediff)) + if (remaintime/IN_MILISECONDS <= int32(timediff)) continue; - remaintime -= timediff; + remaintime -= timediff*IN_MILISECONDS; } // prevent wrong values of remaincharges diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 891e541b6..a7bbcc4a0 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2072,24 +2072,10 @@ void Player::RegenerateHealth(uint32 diff) ModifyHealth(int32(addvalue)); } -bool Player::CanInteractWithNPCs(bool alive) const -{ - if(alive && !isAlive()) - return false; - if(isInFlight()) - return false; - - return true; -} - -Creature* -Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask) +Creature* Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask) { // unit checks - if (!guid) - return NULL; - - if(!IsInWorld()) + if (!guid || !IsInWorld() || isInFlight()) return NULL; // exist (we need look pets also for some interaction (quest/etc) @@ -2097,23 +2083,23 @@ Player::GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask) if (!unit) return NULL; - // player check - if(!CanInteractWithNPCs(!(unit->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GHOST))) - return NULL; - // appropriate npc type - if(npcflagmask && !unit->HasFlag( UNIT_NPC_FLAGS, npcflagmask )) + if (npcflagmask && !unit->HasFlag( UNIT_NPC_FLAGS, npcflagmask )) return NULL; - if (isAlive() && !unit->isAlive()) + // if a dead unit should be able to talk - the creature must be alive and have special flags + if (!unit->isAlive()) + return NULL; + + if (isAlive() && unit->isInvisibleForAlive()) return NULL; // not allow interaction under control, but allow with own pets - if(unit->GetCharmerGUID()) + if (unit->GetCharmerGUID()) return NULL; // not enemy - if( unit->IsHostileTo(this)) + if (unit->IsHostileTo(this)) return NULL; // not unfriendly @@ -14835,10 +14821,10 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff) // negative effects should continue counting down after logout if (remaintime != -1 && !IsPositiveEffect(spellid, effindex)) { - if(remaintime <= int32(timediff)) + if (remaintime/IN_MILISECONDS <= int32(timediff)) continue; - remaintime -= timediff; + remaintime -= timediff*IN_MILISECONDS; } // prevent wrong values of remaincharges diff --git a/src/game/Player.h b/src/game/Player.h index ecfc1228a..8cb49f033 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1046,7 +1046,6 @@ class MANGOS_DLL_SPEC Player : public Unit void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time); Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask); - bool CanInteractWithNPCs(bool alive = true) const; GameObject* GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const; void UpdateVisibilityForPlayer(); diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp index e038add5c..fe38d3f82 100644 --- a/src/game/PoolHandler.cpp +++ b/src/game/PoolHandler.cpp @@ -243,7 +243,7 @@ bool PoolGroup::Spawn1Object(uint32 guid) // Spawn if necessary (loaded grids only) Map* map = const_cast(MapManager::Instance().CreateBaseMap(data->mapid)); // We use spawn coords to spawn - if (!map->Instanceable() && !map->IsRemovalGrid(data->posX, data->posY)) + if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) { Creature* pCreature = new Creature; //sLog.outDebug("Spawning creature %u",guid); @@ -273,7 +273,7 @@ bool PoolGroup::Spawn1Object(uint32 guid) // this base map checked as non-instanced and then only existed Map* map = const_cast(MapManager::Instance().CreateBaseMap(data->mapid)); // We use current coords to unspawn, not spawn coords since creature can have changed grid - if (!map->Instanceable() && !map->IsRemovalGrid(data->posX, data->posY)) + if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) { GameObject* pGameobject = new GameObject; //sLog.outDebug("Spawning gameobject %u", guid); diff --git a/src/game/QuestDef.h b/src/game/QuestDef.h index 02729db1d..d8dc4fabf 100644 --- a/src/game/QuestDef.h +++ b/src/game/QuestDef.h @@ -132,6 +132,9 @@ enum __QuestFlags QUEST_FLAGS_AUTO_REWARDED = 0x00000400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side. QUEST_FLAGS_TBC_RACES = 0x00000800, // Not used currently: Blood elf/Draenei starting zone quests QUEST_FLAGS_DAILY = 0x00001000, // Used to know quest is Daily one + QUEST_FLAGS_UNK3 = 0x00002000, + QUEST_FLAGS_UNK4 = 0x00004000, // ? Membership Card Renewal + QUEST_FLAGS_WEEKLY = 0x00008000, // Not used currently: Weekly quests // Mangos flags for set SpecialFlags in DB if required but used only at server QUEST_MANGOS_FLAGS_REPEATABLE = 0x010000, // Set by 1 in SpecialFlags from DB diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 83945c8e2..45762a66f 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -1883,26 +1883,30 @@ enum CreatureFamily enum CreatureTypeFlags { - CREATURE_TYPEFLAGS_TAMEABLE = 0x00001, //tameable by any hunter - CREATURE_TYPEFLAGS_UNK2 = 0x00002, //? Related to spirits/ghosts in any form? Allow gossip interaction if player is also ghost? Visibility? - CREATURE_TYPEFLAGS_UNK3 = 0x00004, - CREATURE_TYPEFLAGS_UNK4 = 0x00008, - CREATURE_TYPEFLAGS_UNK5 = 0x00010, - CREATURE_TYPEFLAGS_UNK6 = 0x00020, - CREATURE_TYPEFLAGS_UNK7 = 0x00040, - CREATURE_TYPEFLAGS_UNK8 = 0x00080, - CREATURE_TYPEFLAGS_HERBLOOT = 0x00100, //can be looted by herbalist - CREATURE_TYPEFLAGS_MININGLOOT = 0x00200, //can be looted by miner - CREATURE_TYPEFLAGS_UNK11 = 0x00400, - CREATURE_TYPEFLAGS_UNK12 = 0x00800, //? Related to mounts in some way. If mounted, fight mounted, mount appear as independant when rider dies? - CREATURE_TYPEFLAGS_UNK13 = 0x01000, //? Can aid any player in combat if in range? - CREATURE_TYPEFLAGS_UNK14 = 0x02000, - CREATURE_TYPEFLAGS_UNK15 = 0x04000, //? Possibly not in use - CREATURE_TYPEFLAGS_ENGINEERLOOT = 0x08000, //can be looted by engineer - CREATURE_TYPEFLAGS_EXOTIC = 0x10000, //can be tamed by hunter as exotic pet - CREATURE_TYPEFLAGS_UNK18 = 0x20000, //? Related to veichles/pvp? - CREATURE_TYPEFLAGS_UNK19 = 0x40000, //? Related to veichle/siege weapons? - CREATURE_TYPEFLAGS_UNK20 = 0x80000 + CREATURE_TYPEFLAGS_TAMEABLE = 0x000001, // Tameable by any hunter + CREATURE_TYPEFLAGS_GHOST_VISIBLE = 0x000002, // Creatures which can _also_ be seen when player is a ghost + CREATURE_TYPEFLAGS_UNK3 = 0x000004, + CREATURE_TYPEFLAGS_UNK4 = 0x000008, + CREATURE_TYPEFLAGS_UNK5 = 0x000010, + CREATURE_TYPEFLAGS_UNK6 = 0x000020, + CREATURE_TYPEFLAGS_UNK7 = 0x000040, + CREATURE_TYPEFLAGS_UNK8 = 0x000080, + CREATURE_TYPEFLAGS_HERBLOOT = 0x000100, // Can be looted by herbalist + CREATURE_TYPEFLAGS_MININGLOOT = 0x000200, // Can be looted by miner + CREATURE_TYPEFLAGS_UNK11 = 0x000400, + CREATURE_TYPEFLAGS_UNK12 = 0x000800, // ? Related to mounts in some way. If mounted, fight mounted, mount appear as independant when rider dies? + CREATURE_TYPEFLAGS_UNK13 = 0x001000, // ? Can aid any player in combat if in range? + CREATURE_TYPEFLAGS_UNK14 = 0x002000, + CREATURE_TYPEFLAGS_UNK15 = 0x004000, // ? Possibly not in use + CREATURE_TYPEFLAGS_ENGINEERLOOT = 0x008000, // Can be looted by engineer + CREATURE_TYPEFLAGS_EXOTIC = 0x010000, // Can be tamed by hunter as exotic pet + CREATURE_TYPEFLAGS_UNK18 = 0x020000, // ? Related to vehicles/pvp? + CREATURE_TYPEFLAGS_UNK19 = 0x040000, // ? Related to vehicle/siege weapons? + CREATURE_TYPEFLAGS_UNK20 = 0x080000, + CREATURE_TYPEFLAGS_UNK21 = 0x100000, + CREATURE_TYPEFLAGS_UNK22 = 0x200000, + CREATURE_TYPEFLAGS_UNK23 = 0x400000, + CREATURE_TYPEFLAGS_UNK24 = 0x800000 // ? First seen in 3.2.2. Related to banner/backpack of creature/companion? }; enum CreatureEliteType diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 9e56a833b..979fb6f4e 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -3930,7 +3930,7 @@ SpellCastResult Spell::CheckCast(bool strict) if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) return SPELL_FAILED_TARGET_AURASTATE; - if (IsDeathOnlySpell(m_spellInfo) && target->isAlive()) + if (!m_IsTriggeredSpell && IsDeathOnlySpell(m_spellInfo) && target->isAlive()) return SPELL_FAILED_TARGET_NOT_DEAD; // Target aura req check if need @@ -4124,8 +4124,7 @@ SpellCastResult Spell::CheckCast(bool strict) (m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF) || m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES || - // Check possible in DB targets only for spells with no implicit spell focus - (m_spellInfo->EffectImplicitTargetA[j] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT && !m_spellInfo->RequiresSpellFocus)) + m_spellInfo->EffectImplicitTargetA[j] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) { SpellScriptTargetBounds bounds = spellmgr.GetSpellScriptTargetBounds(m_spellInfo->Id); @@ -4242,11 +4241,17 @@ SpellCastResult Spell::CheckCast(bool strict) //Missing DB Entry or targets for this spellEffect. else { - // not report target not existence for triggered spells - if(m_triggeredByAuraSpell || m_IsTriggeredSpell) - return SPELL_FAILED_DONT_REPORT; - else - return SPELL_FAILED_BAD_TARGETS; + /* For TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT makes DB targets optional not required for now + * TODO: Makes more research for this target type + */ + if (m_spellInfo->EffectImplicitTargetA[j] != TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) + { + // not report target not existence for triggered spells + if(m_triggeredByAuraSpell || m_IsTriggeredSpell) + return SPELL_FAILED_DONT_REPORT; + else + return SPELL_FAILED_BAD_TARGETS; + } } } } diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 8015555f8..afed0ac18 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -572,7 +572,7 @@ Aura* CreateAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoi Unit* Aura::GetCaster() const { - if(m_caster_guid==m_target->GetGUID()) + if(m_caster_guid == m_target->GetGUID()) return m_target; //return ObjectAccessor::GetUnit(*m_target,m_caster_guid); @@ -1450,10 +1450,10 @@ void Aura::HandleAddTargetTrigger(bool apply, bool /*Real*/) void Aura::TriggerSpell() { - Unit* caster = GetCaster(); + const uint64& casterGUID = GetCasterGUID(); Unit* target = GetTriggerTarget(); - if(!caster || !target) + if(!casterGUID || !target) return; // generic casting code with custom spells and target/caster customs @@ -1479,9 +1479,9 @@ void Aura::TriggerSpell() case 17949: case 27252: { - if (caster->GetTypeId()!=TYPEID_PLAYER) + if (target->GetTypeId() != TYPEID_PLAYER) return; - Item* item = ((Player*)caster)->GetWeaponForAttack(BASE_ATTACK); + Item* item = ((Player*)target)->GetWeaponForAttack(BASE_ATTACK); if (!item) return; uint32 enchant_id = 0; @@ -1496,10 +1496,10 @@ void Aura::TriggerSpell() return; } // remove old enchanting before applying new - ((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false); + ((Player*)target)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false); item->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, m_modifier.periodictime+1000, 0); // add new enchanting - ((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,true); + ((Player*)target)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,true); return; } // // Periodic Mana Burn @@ -1542,14 +1542,13 @@ void Aura::TriggerSpell() // Restoration case 23493: { - int32 heal = caster->GetMaxHealth() / 10; - caster->DealHeal(caster, heal, auraSpellInfo); + int32 heal = target->GetMaxHealth() / 10; + target->DealHeal(target, heal, auraSpellInfo); - int32 mana = caster->GetMaxPower(POWER_MANA); - if (mana) + if (int32 mana = target->GetMaxPower(POWER_MANA)) { mana /= 10; - caster->EnergizeBySpell(caster, 23493, mana, POWER_MANA); + target->EnergizeBySpell(target, 23493, mana, POWER_MANA); } return; } @@ -1579,7 +1578,7 @@ void Aura::TriggerSpell() case 25371: { int32 bpDamage = target->GetMaxHealth()*10/100; - caster->CastCustomSpell(target, 25373, &bpDamage, NULL, NULL, true, NULL, this); + target->CastCustomSpell(target, 25373, &bpDamage, NULL, NULL, true, NULL, this, casterGUID); return; } // // Pain Spike @@ -1606,7 +1605,7 @@ void Aura::TriggerSpell() case 27808: { int32 bpDamage = target->GetMaxHealth()*26/100; - caster->CastCustomSpell(target, 29879, &bpDamage, NULL, NULL, true, NULL, this); + target->CastCustomSpell(target, 29879, &bpDamage, NULL, NULL, true, NULL, this, casterGUID); return; } // // Detonate Mana @@ -1657,10 +1656,13 @@ void Aura::TriggerSpell() // Extract Gas case 30427: { + Unit* caster = GetCaster(); + if (!caster) + return; // move loot to player inventory and despawn target if(caster->GetTypeId() ==TYPEID_PLAYER && - target->GetTypeId() == TYPEID_UNIT && - ((Creature*)target)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD) + target->GetTypeId() == TYPEID_UNIT && + ((Creature*)target)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD) { Player* player = (Player*)caster; Creature* creature = (Creature*)target; @@ -1700,13 +1702,18 @@ void Aura::TriggerSpell() case 31373: { // Summon Elemental after create item - caster->SummonCreature(17870, 0, 0, 0, caster->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); + target->SummonCreature(17870, 0, 0, 0, target->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); return; } // // Bloodmyst Tesla // case 31611: break; -// // Doomfire -// case 31944: break; + // Doomfire + case 31944: + { + int32 damage = m_modifier.m_amount * ((float)(GetAuraDuration() + m_modifier.periodictime) / GetAuraMaxDuration()); + target->CastCustomSpell(target, 31969, &damage, NULL, NULL, true, NULL, this, casterGUID); + return; + } // // Teleport Test // case 32236: break; // // Earthquake @@ -1722,9 +1729,9 @@ void Aura::TriggerSpell() { // cast 24 spells 34269-34289, 34314-34316 for(uint32 spell_id = 34269; spell_id != 34290; ++spell_id) - caster->CastSpell(m_target, spell_id, true); + target->CastSpell(target, spell_id, true, NULL, this, casterGUID); for(uint32 spell_id = 34314; spell_id != 34317; ++spell_id) - caster->CastSpell(m_target, spell_id, true); + target->CastSpell(target, spell_id, true, NULL, this, casterGUID); return; } // // Gravity Lapse @@ -1815,7 +1822,10 @@ void Aura::TriggerSpell() if(m_target->GetTypeId() != TYPEID_UNIT) return; - caster->CastSpell(caster, 38495, true); + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, 38495, true, NULL, this); + else + return; Creature* creatureTarget = (Creature*)m_target; @@ -2073,7 +2083,7 @@ void Aura::TriggerSpell() bool all = true; for(int i = 0; i < MAX_TOTEM; ++i) { - if(!caster->m_TotemSlot[i]) + if(!target->m_TotemSlot[i]) { all = false; break; @@ -2081,9 +2091,9 @@ void Aura::TriggerSpell() } if(all) - caster->CastSpell(caster, 38437, true); + target->CastSpell(target, 38437, true, NULL, this); else - caster->RemoveAurasDueToSpell(38437); + target->RemoveAurasDueToSpell(38437); return; } default: @@ -2113,14 +2123,14 @@ void Aura::TriggerSpell() // 2) maybe aura must be replace by new with accumulative stat mods instead stacking // prevent cast by triggered auras - if(m_caster_guid == m_target->GetGUID()) + if(casterGUID == target->GetGUID()) return; // stop triggering after each affected stats lost > 90 int32 intelectLoss = 0; int32 spiritLoss = 0; - Unit::AuraList const& mModStat = m_target->GetAurasByType(SPELL_AURA_MOD_STAT); + Unit::AuraList const& mModStat = target->GetAurasByType(SPELL_AURA_MOD_STAT); for(Unit::AuraList::const_iterator i = mModStat.begin(); i != mModStat.end(); ++i) { if ((*i)->GetId() == 1010) @@ -2137,47 +2147,52 @@ void Aura::TriggerSpell() if(intelectLoss <= -90 && spiritLoss <= -90) return; - caster = target; break; } // Mana Tide case 16191: { - caster->CastCustomSpell(target, trigger_spell_id, &m_modifier.m_amount, NULL, NULL, true, NULL, this); + target->CastCustomSpell(target, trigger_spell_id, &m_modifier.m_amount, NULL, NULL, true, NULL, this); return; } // Ground Slam case 33525: - target->CastSpell(target, trigger_spell_id, true); + target->CastSpell(target, trigger_spell_id, true, NULL, this, casterGUID); return; // Beacon of Light case 53563: // original caster must be target (beacon) - m_target->CastSpell(m_target,trigger_spell_id,true,NULL,this,m_target->GetGUID()); + target->CastSpell(target, trigger_spell_id, true, NULL, this, target->GetGUID()); return; } } // All ok cast by default case if(triggeredSpellInfo) - caster->CastSpell(target, triggeredSpellInfo, true, 0, this); - else if(target->GetTypeId()!=TYPEID_UNIT || !Script->EffectDummyCreature(caster, GetId(), GetEffIndex(), (Creature*)target)) - sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex()); + target->CastSpell(target, triggeredSpellInfo, true, NULL, this, casterGUID); + else + { + if (Unit* caster = GetCaster()) + { + if(target->GetTypeId() != TYPEID_UNIT || !Script->EffectDummyCreature(caster, GetId(), GetEffIndex(), (Creature*)target)) + sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex()); + } + } } void Aura::TriggerSpellWithValue() { - Unit* caster = GetCaster(); + const uint64& casterGUID = GetCasterGUID(); Unit* target = GetTriggerTarget(); - if(!caster || !target) + if(!casterGUID || !target) return; // generic casting code with custom spells and target/caster customs uint32 trigger_spell_id = GetSpellProto()->EffectTriggerSpell[m_effIndex]; int32 basepoints0 = this->GetModifier()->m_amount; - caster->CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, NULL, this); + target->CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, NULL, this, casterGUID); } /*********************************************************/ @@ -2457,6 +2472,16 @@ void Aura::HandleAuraDummy(bool apply, bool Real) m_target->PlayDirectSound(14972, (Player *)m_target); } return; + case 10848: + case 36978: + case 40131: + case 27978: + case 33900: + if (apply) + m_target->m_AuraFlags |= UNIT_AURAFLAG_ALIVE_INVISIBLE; + else + m_target->m_AuraFlags |= ~UNIT_AURAFLAG_ALIVE_INVISIBLE; + return; } break; } @@ -6245,9 +6270,6 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real) void Aura::PeriodicTick() { - if (!m_target->isAlive() != IsDeathOnlySpell(GetSpellProto())) - return; - switch(m_modifier.m_auraname) { case SPELL_AURA_PERIODIC_DAMAGE: diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 544a84079..f2971702a 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -2205,31 +2205,6 @@ void SpellMgr::LoadSpellScriptTarget() continue; } - // More checks on TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT - bool ok = true; - for (int i = 0; i < 3; ++i) - { - if (spellProto->EffectImplicitTargetA[i] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT || - spellProto->EffectImplicitTargetB[i] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) - { - if (spellProto->RequiresSpellFocus) - { - sLog.outErrorDb("Table `spell_script_target`: spellId %u for TargetEnty %u of type TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT is wrong because spell has implicit ReqSpellFocus %u.", spellId, targetEntry, spellProto->RequiresSpellFocus); - ok = false; - break; - } - - if (type != SPELL_TARGET_TYPE_GAMEOBJECT) - { - sLog.outErrorDb("Table `spell_script_target`: spellId %u has target type TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT but target in table is creature (must be gameobject).", spellId); - ok = false; - break; - } - } - } - if (!ok) - continue; - // Checks by target type switch (type) { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 6518b56c6..c145d17ad 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -104,6 +104,7 @@ Unit::Unit() //m_AurasCheck = 2000; //m_removeAuraTimer = 4; m_AurasUpdateIterator = m_Auras.end(); + m_AuraFlags = 0; m_Visibility = VISIBILITY_ON; @@ -5386,6 +5387,12 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu triggered_spell_id = 63106; break; } + // Glyph of Life Tap + case 63320: + { + triggered_spell_id = 63321; + break; + } } break; } @@ -6276,8 +6283,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu case 10605: spellId = 45300; break; // Rank 4 case 25439: spellId = 45301; break; // Rank 5 case 25442: spellId = 45302; break; // Rank 6 - case 49268: spellId = 49270; break; // Rank 7 - case 49269: spellId = 49271; break; // Rank 8 + case 49270: spellId = 49268; break; // Rank 7 + case 49271: spellId = 49269; break; // Rank 8 default: sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); return false; @@ -9603,11 +9610,10 @@ bool Unit::isTargetableForAttack(bool inverseAlive /*=false*/) const if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return false; - // target is dead or has ghost-flag - if ((!isAlive() || (GetTypeId() == TYPEID_UNIT && ((Creature *)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GHOST)) != inverseAlive) + if ((isAlive() && !isInvisibleForAlive()) == inverseAlive) return false; - return IsInWorld() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/; + return IsInWorld() && !hasUnitState(UNIT_STAT_DIED) && !isInFlight(); } int32 Unit::ModifyHealth(int32 dVal) @@ -9701,7 +9707,7 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo Map& _map = *u->GetMap(); // Grid dead/alive checks - if( u->GetTypeId()==TYPEID_PLAYER) + if (u->GetTypeId()==TYPEID_PLAYER) { // non visible at grid for any stealth state if(!IsVisibleInGridForPlayer((Player *)u)) @@ -9719,15 +9725,15 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo } // always seen by owner - if(GetCharmerOrOwnerGUID()==u->GetGUID()) + if (GetCharmerOrOwnerGUID()==u->GetGUID()) return true; // always seen by far sight caster - if( u->GetTypeId()==TYPEID_PLAYER && ((Player*)u)->GetFarSight()==GetGUID()) + if (u->GetTypeId()==TYPEID_PLAYER && ((Player*)u)->GetFarSight()==GetGUID()) return true; // different visible distance checks - if(u->isInFlight()) // what see player in flight + if (u->isInFlight()) // what see player in flight { // use object grey distance for all (only see objects any way) if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) @@ -9766,6 +9772,10 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo return false; } + if (u->isAlive() && isInvisibleForAlive()) + if (u->GetTypeId() == TYPEID_PLAYER && !((Player *)u)->isGameMaster()) + return false; + // Visible units, always are visible for all units, except for units under invisibility and phases if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask==0 && InSamePhase(u)) return true; @@ -10622,6 +10632,15 @@ bool Unit::isVisibleForInState( Player const* u, WorldObject const* viewPoint, b return isVisibleForOrDetect(u, viewPoint, false, inVisibleList, false); } +/// returns true if creature can't be seen by alive units +bool Unit::isInvisibleForAlive() const +{ + if (m_AuraFlags & UNIT_AURAFLAG_ALIVE_INVISIBLE) + return true; + // TODO: maybe spiritservices also have just an aura + return isSpiritService(); +} + uint32 Unit::GetCreatureType() const { if(GetTypeId() == TYPEID_PLAYER) diff --git a/src/game/Unit.h b/src/game/Unit.h index 48d53db0b..95a062647 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -469,6 +469,12 @@ enum DamageEffectType SELF_DAMAGE = 5 }; +/// internal used flags for marking special auras - for example some dummy-auras +enum UnitAuraFlags +{ + UNIT_AURAFLAG_ALIVE_INVISIBLE = 0x1, // aura which makes unit invisible for alive +}; + enum UnitVisibility { VISIBILITY_OFF = 0, // absolute, not detectable, GM-like, can see all other @@ -1329,6 +1335,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject bool isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const; // function for low level grid visibility checks in player/creature cases virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; + bool isInvisibleForAlive() const; AuraList & GetSingleCastAuras() { return m_scAuras; } AuraList const& GetSingleCastAuras() const { return m_scAuras; } @@ -1389,6 +1396,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject Aura* GetDummyAura(uint32 spell_id) const; + uint32 m_AuraFlags; + uint32 GetDisplayId() { return GetUInt32Value(UNIT_FIELD_DISPLAYID); } void SetDisplayId(uint32 modelId); uint32 GetNativeDisplayId() { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index d993e1e04..40114edfa 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8677" + #define REVISION_NR "8700" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index 55c964243..cfd08a92e 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ #define REVISION_DB_CHARACTERS "required_8596_01_characters_bugreport" - #define REVISION_DB_MANGOS "required_8676_01_mangos_creature_template" + #define REVISION_DB_MANGOS "required_8693_01_mangos_spell_proc_event" #define REVISION_DB_REALMD "required_8332_01_realmd_realmcharacters" #endif // __REVISION_SQL_H__