diff --git a/sql/updates/world/4.3.4/2025_03_11_00_world.sql b/sql/updates/world/4.3.4/2025_03_11_00_world.sql new file mode 100644 index 0000000000..71d820d073 --- /dev/null +++ b/sql/updates/world/4.3.4/2025_03_11_00_world.sql @@ -0,0 +1,11 @@ +-- +ALTER TABLE `creature` + MODIFY COLUMN `npcflag` bigint UNSIGNED NULL DEFAULT NULL AFTER `MovementType`, + MODIFY COLUMN `unit_flags` int UNSIGNED NULL DEFAULT NULL AFTER `npcflag`, + ADD `unit_flags2` int UNSIGNED NULL DEFAULT NULL AFTER `unit_flags`, + MODIFY COLUMN `dynamicflags` int UNSIGNED NULL DEFAULT NULL AFTER `unit_flags2`; + +UPDATE `creature` SET `npcflag`= NULL WHERE `npcflag`=0; +UPDATE `creature` SET `unit_flags`= NULL WHERE `unit_flags`=0; +UPDATE `creature` SET `unit_flags2`= NULL WHERE `unit_flags2`=0; +UPDATE `creature` SET `dynamicflags`= NULL WHERE `dynamicflags`=0; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index d2961a996c..170eb5dd30 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -581,23 +581,23 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, SetFaction(cInfo->faction); - uint32 npcflag, unit_flags, unit_flags2, dynamicflags; - ObjectMgr::ChooseCreatureFlags(cInfo, npcflag, unit_flags, unit_flags2, dynamicflags, _staticFlags, data); + uint32 npcflags, unitFlags, unitFlags2, dynamicFlags; + ObjectMgr::ChooseCreatureFlags(cInfo, &npcflags, &unitFlags, &unitFlags2, &dynamicFlags, _staticFlags, data); if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT) - SetUInt32Value(UNIT_NPC_FLAGS, npcflag | sGameEventMgr->GetNPCFlag(this)); - else - SetUInt32Value(UNIT_NPC_FLAGS, npcflag); + npcflags |= sGameEventMgr->GetNPCFlag(this); + + SetUInt32Value(UNIT_NPC_FLAGS, npcflags); // if unit is in combat, keep this flag - unit_flags &= ~UNIT_FLAG_IN_COMBAT; + unitFlags &= ~UNIT_FLAG_IN_COMBAT; if (IsInCombat()) - unit_flags |= UNIT_FLAG_IN_COMBAT; + unitFlags |= UNIT_FLAG_IN_COMBAT; - SetUInt32Value(UNIT_FIELD_FLAGS, unit_flags); - SetUInt32Value(UNIT_FIELD_FLAGS_2, cInfo->unit_flags2 | unit_flags2); + SetUInt32Value(UNIT_FIELD_FLAGS, unitFlags); + SetUInt32Value(UNIT_FIELD_FLAGS_2, unitFlags2); - SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynamicflags); + SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynamicFlags); SetCanDualWield(cInfo->flags_extra & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK); @@ -1976,13 +1976,15 @@ void Creature::setDeathState(DeathState s) CreatureData const* creatureData = GetCreatureData(); CreatureTemplate const* cinfo = GetCreatureTemplate(); - uint32 npcflag, unit_flags, unit_flags2, dynamicflags; - ObjectMgr::ChooseCreatureFlags(cinfo, npcflag, unit_flags, unit_flags2, dynamicflags, _staticFlags, creatureData); + uint32 npcflag, unitFlags, unitFlags2, dynamicFlags; + ObjectMgr::ChooseCreatureFlags(cinfo, &npcflag, &unitFlags, &unitFlags2, &dynamicFlags, _staticFlags, creatureData); SetUInt32Value(UNIT_NPC_FLAGS, npcflag); - SetUInt32Value(UNIT_FIELD_FLAGS, unit_flags); - SetUInt32Value(UNIT_FIELD_FLAGS_2, cinfo->unit_flags2 | unit_flags2); - SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynamicflags); + SetUInt32Value(UNIT_FIELD_FLAGS, unitFlags); + SetUInt32Value(UNIT_FIELD_FLAGS_2, unitFlags2); + SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynamicFlags); + + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); } diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index e9f04802e6..3498946629 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -505,9 +505,10 @@ struct CreatureData : public SpawnData uint32 curhealth = 0; uint32 curmana = 0; uint8 movementType = 0; - uint32 npcflag = 0; - uint32 unit_flags = 0; - uint32 dynamicflags = 0; + Optional dynamicflags; + Optional npcflag; + Optional unit_flags; // enum UnitFlags mask values + Optional unit_flags2; // enum UnitFlags2 mask values }; struct CreatureModelInfo diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index b836ec9320..3929596219 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1585,36 +1585,45 @@ CreatureModel const* ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, C return cinfo->GetFirstInvisibleModel(); } -void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& unitFlags2, uint32& dynamicflags, CreatureStaticFlagsHolder const& staticFlags, CreatureData const* data /*= nullptr*/) +void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cInfo, uint32* npcFlags, uint32* unitFlags, uint32* unitFlags2, uint32* dynamicFlags, CreatureStaticFlagsHolder const& staticFlags, CreatureData const* data /*= nullptr*/) { - npcflag = cinfo->npcflag; - unit_flags = cinfo->unit_flags; - dynamicflags = cinfo->dynamicflags; - unitFlags2 = 0; +#define ChooseCreatureFlagSource(field) ((data && data->field.has_value()) ? *data->field : cInfo->field) if (data) { - if (data->npcflag) - npcflag = data->npcflag; + if (npcFlags) + *npcFlags = ChooseCreatureFlagSource(npcflag); - if (data->unit_flags) - unit_flags = data->unit_flags; + if (unitFlags) + { + *unitFlags = ChooseCreatureFlagSource(unit_flags); - if (data->dynamicflags) - dynamicflags = data->dynamicflags; + if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_CAN_SWIM)) + *unitFlags |= UNIT_FLAG_CAN_SWIM; + + if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_SWIM)) + *unitFlags |= UNIT_FLAG_CANT_SWIM; + } + + if (unitFlags2) + { + *unitFlags2 = ChooseCreatureFlagSource(unit_flags2); + + if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_TURN)) + *unitFlags2 |= UNIT_FLAG2_CANNOT_TURN; + + if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_PREVENT_SWIM)) + *unitFlags2 |= UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS; + } + + if (dynamicFlags) + { + *dynamicFlags = ChooseCreatureFlagSource(dynamicflags); + } } - if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_CAN_SWIM)) - unit_flags |= UNIT_FLAG_CAN_SWIM; - if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_SWIM)) - unit_flags |= UNIT_FLAG_CANT_SWIM; - - if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_TURN)) - unitFlags2 |= UNIT_FLAG2_CANNOT_TURN; - - if (staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_PREVENT_SWIM)) - unitFlags2 |= UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS; +#undef ChooseCreatureFlagSource } CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(CreatureModel* model, CreatureTemplate const* creatureTemplate) const @@ -2035,9 +2044,9 @@ void ObjectMgr::LoadCreatures() // 0 1 2 3 4 5 6 7 8 9 10 QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, position_x, position_y, position_z, orientation, modelid, equipment_id, spawntimesecs, wander_distance, " - // 11 12 13 14 15 16 17 18 19 20 21 - "currentwaypoint, curhealth, curmana, MovementType, spawnMask, eventEntry, poolSpawnId, creature.npcflag, creature.unit_flags, creature.dynamicflags, creature.phaseUseFlags, " - // 22 23 24 25 + // 11 12 13 14 15 16 17 18 19 20 21 22 + "currentwaypoint, curhealth, curmana, MovementType, spawnMask, eventEntry, poolSpawnId, creature.npcflag, creature.unit_flags, creature.unit_flags, creature.dynamicflags, creature.phaseUseFlags, " + // 23 24 25 26 "creature.PhaseId, creature.PhaseGroup, creature.terrainSwapMap, creature.ScriptName " "FROM creature " "LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid " @@ -2091,14 +2100,19 @@ void ObjectMgr::LoadCreatures() data.spawnMask = fields[15].GetUInt8(); int16 gameEvent = fields[16].GetInt8(); data.poolId = fields[17].GetUInt32(); - data.npcflag = fields[18].GetUInt32(); - data.unit_flags = fields[19].GetUInt32(); - data.dynamicflags = fields[20].GetUInt32(); - data.phaseUseFlags = fields[21].GetUInt8(); - data.phaseId = fields[22].GetUInt32(); - data.phaseGroup = fields[23].GetUInt32(); - data.terrainSwapMap = fields[24].GetInt32(); - data.scriptId = GetScriptId(fields[25].GetString()); + if (!fields[18].IsNull()) + data.npcflag = fields[18].GetUInt64(); + if (!fields[19].IsNull()) + data.unit_flags = fields[19].GetUInt32(); + if (!fields[20].IsNull()) + data.unit_flags2 = fields[20].GetUInt32(); + if (!fields[21].IsNull()) + data.dynamicflags = fields[21].GetUInt32(); + data.phaseUseFlags = fields[22].GetUInt8(); + data.phaseId = fields[23].GetUInt32(); + data.phaseGroup = fields[24].GetUInt32(); + data.terrainSwapMap = fields[25].GetInt32(); + data.scriptId = GetScriptId(fields[26].GetString()); data.spawnGroupData = GetDefaultSpawnGroup(); MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapId); @@ -2219,6 +2233,26 @@ void ObjectMgr::LoadCreatures() } } + /* + if (data.unit_flags.has_value()) + { + if (uint32 disallowedUnitFlags = (*data.unit_flags & ~UNIT_FLAG_ALLOWED)) + { + TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: {} Entry: {}) with disallowed `unit_flags` {}, removing incorrect flag.", guid, data.id, disallowedUnitFlags); + *data.unit_flags &= UNIT_FLAG_ALLOWED; + } + } + + if (data.unit_flags2.has_value()) + { + if (uint32 disallowedUnitFlags2 = (*data.unit_flags2 & ~UNIT_FLAG2_ALLOWED)) + { + TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: {} Entry: {}) with disallowed `unit_flags2` {}, removing incorrect flag.", guid, data.id, disallowedUnitFlags2); + *data.unit_flags2 &= UNIT_FLAG2_ALLOWED; + } + } + */ + if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA)) { uint32 zoneId = 0; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 5bdd08a206..d3ed75f9d9 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1013,7 +1013,7 @@ class TC_GAME_API ObjectMgr CreatureModelInfo const* GetCreatureModelInfo(uint32 modelId) const; CreatureModelInfo const* GetCreatureModelRandomGender(CreatureModel* model, CreatureTemplate const* creatureTemplate) const; static CreatureModel const* ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = nullptr); - static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& unitFlags2, uint32& dynamicflags, CreatureStaticFlagsHolder const& staticFlags, CreatureData const* data = nullptr); + static void ChooseCreatureFlags(CreatureTemplate const* cInfo, uint32* npcFlags, uint32* unitFlags, uint32* unitFlags2, uint32* dynamicFlags, CreatureStaticFlagsHolder const& staticFlags, CreatureData const* data /*= nullptr*/); EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id) const; CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid) const; GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid) const;