diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 8f75cd34f28..231e0b3342f 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1006,6 +1006,9 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) data.unit_flags = unit_flags; data.dynamicflags = dynamicflags; + data.phaseid = GetDBPhase() > 0 ? GetDBPhase() : 0; + data.phaseGroup = GetDBPhase() < 0 ? abs(GetDBPhase()) : 0; + // update in DB SQLTransaction trans = WorldDatabase.BeginTransaction(); @@ -1021,6 +1024,8 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) stmt->setUInt16(index++, uint16(mapid)); stmt->setUInt8(index++, spawnMask); stmt->setUInt32(index++, GetPhaseMask()); + stmt->setUInt32(index++, data.phaseid); + stmt->setUInt32(index++, data.phaseGroup); stmt->setUInt32(index++, displayId); stmt->setInt32(index++, int32(GetCurrentEquipmentId())); stmt->setFloat(index++, GetPositionX()); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 6592e2a6b8f..beb8a13ed4b 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1286,7 +1286,7 @@ void MovementInfo::OutDebug() WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0), m_name(""), m_isActive(false), m_isWorldObject(isWorldObject), m_zoneScript(NULL), m_transport(NULL), m_currMap(NULL), m_InstanceId(0), -m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0), m_executed_notifies(0) +m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); @@ -2720,11 +2720,13 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) void WorldObject::SetInPhase(uint32 id, bool update, bool apply) { - if (apply) - _phases.insert(id); - else - _phases.erase(id); - + if (id) + { + if (apply) + _phases.insert(id); + else + _phases.erase(id); + } RebuildTerrainSwaps(); if (update && IsInWorld()) @@ -2743,6 +2745,16 @@ void WorldObject::CopyPhaseFrom(WorldObject* obj, bool update) UpdateObjectVisibility(); } +void WorldObject::ClearPhases(bool update) +{ + _phases.clear(); + + RebuildTerrainSwaps(); + + if (update && IsInWorld()) + UpdateObjectVisibility(); +} + bool WorldObject::IsInPhase(WorldObject const* obj) const { // PhaseId 169 is the default fallback phase diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index ecfdec36e09..71f1cc69dfe 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -594,6 +594,7 @@ class WorldObject : public Object, public WorldLocation virtual void SetPhaseMask(uint32 newPhaseMask, bool update); virtual void SetInPhase(uint32 id, bool update, bool apply); void CopyPhaseFrom(WorldObject* obj, bool update = false); + void ClearPhases(bool update = false); void RebuildTerrainSwaps(); uint32 GetPhaseMask() const { return m_phaseMask; } bool IsInPhase(uint32 phase) const { return _phases.find(phase) != _phases.end(); } @@ -601,6 +602,10 @@ class WorldObject : public Object, public WorldLocation bool IsInTerrainSwap(uint32 terrainSwap) const { return _terrainSwaps.find(terrainSwap) != _terrainSwaps.end(); } std::set const& GetPhases() const { return _phases; } std::set const& GetTerrainSwaps() const { return _terrainSwaps; } + int GetDBPhase() { return _dbPhase; } + + // if negative it is used as PhaseGroupId + void SetDBPhase(int p) { _dbPhase = p; } uint32 GetZoneId() const; uint32 GetAreaId() const; @@ -773,6 +778,7 @@ class WorldObject : public Object, public WorldLocation uint32 m_phaseMask; // in area phase state std::set _phases; std::set _terrainSwaps; + int _dbPhase; uint16 m_notifyflags; uint16 m_executed_notifies; diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index d94ffe51f42..e27fc8d7a21 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -181,19 +181,19 @@ public: { "temp", rbac::RBAC_PERM_COMMAND_NPC_ADD_TEMP, false, &HandleNpcAddTempSpawnCommand, "", NULL }, //{ "weapon", rbac::RBAC_PERM_COMMAND_NPC_ADD_WEAPON, false, &HandleNpcAddWeaponCommand, "", NULL }, { "", rbac::RBAC_PERM_COMMAND_NPC_ADD, false, &HandleNpcAddCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } + { NULL, 0, false, NULL, "", NULL } }; static ChatCommand npcDeleteCommandTable[] = { { "item", rbac::RBAC_PERM_COMMAND_NPC_DELETE_ITEM, false, &HandleNpcDeleteVendorItemCommand, "", NULL }, { "", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, &HandleNpcDeleteCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } + { NULL, 0, false, NULL, "", NULL } }; static ChatCommand npcFollowCommandTable[] = { { "stop", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW_STOP, false, &HandleNpcUnFollowCommand, "", NULL }, { "", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, &HandleNpcFollowCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } + { NULL, 0, false, NULL, "", NULL } }; static ChatCommand npcSetCommandTable[] = { @@ -206,12 +206,13 @@ public: { "model", rbac::RBAC_PERM_COMMAND_NPC_SET_MODEL, false, &HandleNpcSetModelCommand, "", NULL }, { "movetype", rbac::RBAC_PERM_COMMAND_NPC_SET_MOVETYPE, false, &HandleNpcSetMoveTypeCommand, "", NULL }, { "phase", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseCommand, "", NULL }, + { "phasegroup", rbac::RBAC_PERM_COMMAND_NPC_SET_DATA, false, &HandleNpcSetPhaseGroup, "", NULL }, { "spawndist", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNDIST, false, &HandleNpcSetSpawnDistCommand, "", NULL }, { "spawntime", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNTIME, false, &HandleNpcSetSpawnTimeCommand, "", NULL }, { "data", rbac::RBAC_PERM_COMMAND_NPC_SET_DATA, false, &HandleNpcSetDataCommand, "", NULL }, //{ "name", rbac::RBAC_PERM_COMMAND_NPC_SET_NAME, false, &HandleNpcSetNameCommand, "", NULL }, //{ "subname", rbac::RBAC_PERM_COMMAND_NPC_SET_SUBNAME, false, &HandleNpcSetSubNameCommand, "", NULL }, - { NULL, 0, false, NULL, "", NULL } + { NULL, 0, false, NULL, "", NULL } }; static ChatCommand npcCommandTable[] = { @@ -228,7 +229,7 @@ public: { "delete", rbac::RBAC_PERM_COMMAND_NPC_DELETE, false, NULL, "", npcDeleteCommandTable }, { "follow", rbac::RBAC_PERM_COMMAND_NPC_FOLLOW, false, NULL, "", npcFollowCommandTable }, { "set", rbac::RBAC_PERM_COMMAND_NPC_SET, false, NULL, "", npcSetCommandTable }, - { NULL, 0, false, NULL, "", NULL } + { NULL, 0, false, NULL, "", NULL } }; static ChatCommand commandTable[] = { @@ -272,6 +273,8 @@ public: Creature* creature = trans->CreateNPCPassenger(guid, &data); + // creature->CopyPhaseFrom(chr); // will not be saved, and probably useless + creature->SaveToDB(trans->GetGOInfo()->moTransport.mapID, 1 << map->GetSpawnMode(), chr->GetPhaseMask()); sObjectMgr->AddCreatureToGrid(guid, &data); @@ -285,7 +288,7 @@ public: return false; } - creature->CopyPhaseFrom(chr); + //creature->CopyPhaseFrom(chr); // creature is not directly added to world, only to db, so this is useless here creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); @@ -1099,7 +1102,37 @@ public: } //npc phase handling - //change phase of creature or pet + //change phase of creature + static bool HandleNpcSetPhaseGroup(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + uint32 phaseGroupId = (uint32)atoi((char*)args); + + Creature* creature = handler->getSelectedCreature(); + if (!creature || creature->IsPet()) + { + handler->SendSysMessage(LANG_SELECT_CREATURE); + handler->SetSentErrorMessage(true); + return false; + } + + creature->ClearPhases(); + + for (uint32 id : GetPhasesForGroup(phaseGroupId)) + creature->SetInPhase(id, false, true); // don't send update here for multiple phases, only send it once after adding all phases + + creature->UpdateObjectVisibility(); + creature->SetDBPhase(-int(phaseGroupId)); + + creature->SaveToDB(); + + return true; + } + + //npc phase handling + //change phase of creature static bool HandleNpcSetPhaseCommand(ChatHandler* handler, char const* args) { if (!*args) @@ -1108,17 +1141,18 @@ public: uint32 phase = (uint32) atoi((char*)args); Creature* creature = handler->getSelectedCreature(); - if (!creature) + if (!creature || creature->IsPet()) { handler->SendSysMessage(LANG_SELECT_CREATURE); handler->SetSentErrorMessage(true); return false; } - creature->SetInPhase(phase, true, !creature->IsInPhase(phase)); + creature->ClearPhases(); + creature->SetInPhase(phase, true, true); + creature->SetDBPhase(phase); - if (!creature->IsPet()) - creature->SaveToDB(); + creature->SaveToDB(); return true; } diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index 531d092d039..7ee59db99b2 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -82,7 +82,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM creature WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); - PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, phaseMask, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, phaseMask, PhaseId, PhaseGroup, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_CREATURE, "DELETE FROM game_event_creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_MODEL_EQUIP, "DELETE FROM game_event_model_equip WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);