Core/Movement: ported most movement updates from master branch and corrected behavior of CREATURE_STATIC_FLAG_4_PREVENT_SWIM

This commit is contained in:
Ovahlord committed 2025-03-09 20:49:41 +01:00
1 parent 83958342d9
commit 2953efb7a3
22 files changed
+306 -314

No files matched your search

@@ -0,0 +1,26 @@
-- Add new movement settings
ALTER TABLE `creature_template_movement`
ADD COLUMN `HoverInitiallyEnabled` TINYINT UNSIGNED NULL AFTER `CreatureId`;
UPDATE `creature_template_movement` SET `HoverInitiallyEnabled`= 1 WHERE `Ground` = 2;
ALTER TABLE `creature_movement_override`
ADD COLUMN `HoverInitiallyEnabled` TINYINT UNSIGNED NULL AFTER `SpawnId`;
UPDATE `creature_movement_override` SET `HoverInitiallyEnabled`= 1 WHERE `Ground` = 2;
-- Remove deprecated CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE
UPDATE `creature_template` SET `flags_extra`= `flags_extra` &~ 0x200;
-- Conversion done. Drop old columns
ALTER TABLE `creature_movement_override`
DROP COLUMN `Ground`,
DROP COLUMN `Swim`,
DROP COLUMN `Flight`,
DROP COLUMN `Rooted`;
ALTER TABLE `creature_template_movement`
DROP COLUMN `Ground`,
DROP COLUMN `Swim`,
DROP COLUMN `Flight`,
DROP COLUMN `Rooted`;
+2 -1
View File
@@ -128,7 +128,8 @@ enum ZLiquidStatus : uint32
LIQUID_MAP_ABOVE_WATER = 0x00000001,
LIQUID_MAP_WATER_WALK = 0x00000002,
LIQUID_MAP_IN_WATER = 0x00000004,
LIQUID_MAP_UNDER_WATER = 0x00000008
LIQUID_MAP_UNDER_WATER = 0x00000008,
LIQUID_MAP_OCEAN_FLOOR = 0x00000010
};
#define MAP_LIQUID_STATUS_SWIMMING (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)
@@ -76,7 +76,7 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.HoverInitiallyEnabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH);
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);
@@ -145,9 +145,9 @@ void BattlegroundIC::PostUpdateImpl(uint32 diff)
{
if (siege->IsAlive())
{
if (siege->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_CANNOT_SWIM|UNIT_FLAG_IMMUNE_TO_PC))
if (siege->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_CANT_SWIM | UNIT_FLAG_IMMUNE_TO_PC))
// following sniffs the vehicle always has UNIT_FLAG_CANNOT_SWIM
siege->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_IMMUNE_TO_PC);
siege->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_PC);
else
siege->SetHealth(siege->GetMaxHealth());
}
@@ -753,7 +753,7 @@ void BattlegroundIC::HandleCapturedNodes(ICNodePoint* node, bool recapture)
if (Creature* siegeEngine = GetBGCreature(siegeType))
{
siegeEngine->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_CANNOT_SWIM);
siegeEngine->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_CANT_SWIM);
siegeEngine->SetImmuneToPC(true);
siegeEngine->SetFaction(BG_IC_Factions[(node->faction == TEAM_ALLIANCE ? 0 : 1)]);
}
+2 -2
View File
@@ -368,14 +368,14 @@ bool CombatManager::UpdateOwnerCombatState() const
if (combatState)
{
_owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
_owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT | UNIT_FLAG_PET_IN_COMBAT);
_owner->AtEnterCombat();
if (_owner->GetTypeId() != TYPEID_UNIT)
_owner->AtEngage(GetAnyTarget());
}
else
{
_owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
_owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT | UNIT_FLAG_PET_IN_COMBAT);
_owner->AtExitCombat();
if (_owner->GetTypeId() != TYPEID_UNIT)
_owner->AtDisengage();
+61 -119
View File
@@ -61,24 +61,18 @@
VendorItemCount::VendorItemCount(uint32 _item, uint32 _count)
: itemId(_item), count(_count), lastIncrementTime(GameTime::GetGameTime()) { }
CreatureMovementData::CreatureMovementData() : Ground(CreatureGroundMovementType::Run), Flight(CreatureFlightMovementType::None),
Swim(true), Rooted(false), Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) { }
CreatureMovementData::CreatureMovementData() : HoverInitiallyEnabled(false), Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) { }
std::string CreatureMovementData::ToString() const
{
char const* const GroundStates[] = { "None", "Run", "Hover" };
char const* const FlightStates[] = { "None", "DisableGravity", "CanFly" };
char const* const RandomStates[] = { "Walk", "CanRun", "AlwaysRun" };
std::ostringstream str;
str << std::boolalpha
<< "Ground: " << GroundStates[AsUnderlyingType(Ground)]
<< ", Swim: " << Swim
<< ", Flight: " << FlightStates[AsUnderlyingType(Flight)]
<< ", Random: " << RandomStates[AsUnderlyingType(Random)];
if (Rooted)
str << ", Rooted";
<< ", HoverInitiallyEnabled: " << HoverInitiallyEnabled
<< "Random: " << RandomStates[AsUnderlyingType(Random)];
str << ", InteractionPauseTimer: " << InteractionPauseTimer;
return str.str();
@@ -589,8 +583,8 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
SetFaction(cInfo->faction);
uint32 npcflag, unit_flags, dynamicflags;
ObjectMgr::ChooseCreatureFlags(cInfo, npcflag, unit_flags, dynamicflags, data);
uint32 npcflag, unit_flags, unit_flags2, dynamicflags;
ObjectMgr::ChooseCreatureFlags(cInfo, npcflag, unit_flags, unit_flags2, dynamicflags, _staticFlags, data);
if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT)
SetUInt32Value(UNIT_NPC_FLAGS, npcflag | sGameEventMgr->GetNPCFlag(this));
@@ -603,7 +597,7 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
unit_flags |= UNIT_FLAG_IN_COMBAT;
SetUInt32Value(UNIT_FIELD_FLAGS, unit_flags);
SetUInt32Value(UNIT_FIELD_FLAGS_2, cInfo->unit_flags2);
SetUInt32Value(UNIT_FIELD_FLAGS_2, cInfo->unit_flags2 | unit_flags2);
SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynamicflags);
@@ -662,13 +656,12 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
}
if (GetMovementTemplate().IsRooted())
SetControlled(true, UNIT_STATE_ROOT);
if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_COMBAT)
SetIgnoringCombat(true);
InitializeMovementFlags();
InitializeMovementCapabilities();
LoadCreaturesAddon();
LoadTemplateImmunities();
@@ -680,8 +673,7 @@ void Creature::ApplyAllStaticFlags(CreatureStaticFlagsHolder const& flags)
{
_staticFlags = flags;
// Apply all other side effects of flag changes
SetTemplateRooted(flags.HasFlag(CREATURE_STATIC_FLAG_SESSILE));
m_updateFlag.NoBirthAnim = flags.HasFlag(CREATURE_STATIC_FLAG_4_NO_BIRTH_ANIM);
}
void Creature::Update(uint32 diff)
@@ -694,7 +686,7 @@ void Creature::Update(uint32 diff)
AI()->JustAppeared();
}
UpdateMovementFlags(false);
UpdateMovementCapabilities();
GetThreatManager().Update(diff);
@@ -1110,7 +1102,7 @@ bool Creature::SetDisableGravity(bool disable, bool packetOnly /*= false*/, bool
if (!Unit::SetDisableGravity(disable, packetOnly, updateAnimationTier))
return false;
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !GetMovementTemplate().IsRooted())
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT))
{
if (IsGravityDisabled())
SetAnimationTier(AnimationTier::Fly);
@@ -1132,7 +1124,7 @@ bool Creature::SetHover(bool enable, bool packetOnly /*= false*/, bool updateAni
if (!Unit::SetHover(enable, packetOnly, updateAnimationTier))
return false;
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !GetMovementTemplate().IsRooted())
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT))
{
if (IsGravityDisabled())
SetAnimationTier(AnimationTier::Fly);
@@ -1727,17 +1719,6 @@ void Creature::SetSpawnHealth()
SetHealth((m_deathState == ALIVE || m_deathState == JUST_RESPAWNED) ? curhealth : 0);
}
void Creature::LoadTemplateRoot()
{
SetTemplateRooted(GetMovementTemplate().IsRooted());
}
void Creature::SetTemplateRooted(bool rooted)
{
_staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_SESSILE, rooted);
SetControlled(rooted, UNIT_STATE_ROOT);
}
bool Creature::hasQuest(uint32 quest_id) const
{
return sObjectMgr->GetCreatureQuestRelations(GetEntry()).HasQuest(quest_id);
@@ -1968,7 +1949,7 @@ void Creature::setDeathState(DeathState s)
if (m_formation && m_formation->getLeader() == this)
m_formation->FormationReset(true);
bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater();
bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater() && !HasUnitState(UNIT_STATE_ROOT);
SetHover(false, false);
SetDisableGravity(false, false);
@@ -1988,7 +1969,7 @@ void Creature::setDeathState(DeathState s)
ResetPlayerDamageReq();
SetCannotReachTarget(false);
UpdateMovementFlags(true);
UpdateMovementCapabilities();
ClearUnitState(UNIT_STATE_ALL_ERASABLE);
@@ -1997,11 +1978,12 @@ void Creature::setDeathState(DeathState s)
CreatureData const* creatureData = GetCreatureData();
CreatureTemplate const* cinfo = GetCreatureTemplate();
uint32 npcflag, unit_flags, dynamicflags;
ObjectMgr::ChooseCreatureFlags(cinfo, npcflag, unit_flags, dynamicflags, creatureData);
uint32 npcflag, unit_flags, unit_flags2, dynamicflags;
ObjectMgr::ChooseCreatureFlags(cinfo, npcflag, unit_flags, unit_flags2, 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);
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
@@ -2527,7 +2509,7 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const
dist += GetCombatReach() + victim->GetCombatReach();
// to prevent creatures in air ignore attacks because distance is already too high...
if (GetMovementTemplate().IsFlightAllowed())
if (CanFly())
return victim->IsInDist2d(&m_homePosition, dist);
else
return victim->IsInDist(&m_homePosition, dist);
@@ -2561,14 +2543,6 @@ bool Creature::LoadCreaturesAddon()
SetAnimationTier(AnimationTier(creatureAddon->animTier));
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_VIS_FLAG, creatureAddon->visFlags);
//! Suspected correlation between UNIT_FIELD_BYTES_1, offset 3, value 0x2:
//! If no inhabittype_fly (if no MovementFlag_DisableGravity or MovementFlag_CanFly flag found in sniffs)
//! Check using InhabitType as movement flags are assigned dynamically
//! basing on whether the creature is in air or not
//! Set MovementFlag_Hover. Otherwise do nothing.
if (CanHover())
AddUnitMovementFlag(MOVEMENTFLAG_HOVER);
// UNIT_FIELD_BYTES_2 values
SetSheath(SheathState(creatureAddon->sheathState));
SetByteValue(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, creatureAddon->pvpFlags);
@@ -2672,6 +2646,45 @@ void Creature::GetRespawnPosition(float &x, float &y, float &z, float* ori, floa
}
}
void Creature::InitializeMovementCapabilities()
{
SetHover(GetMovementTemplate().IsHoverInitiallyEnabled());
SetDisableGravity(IsFloating());
SetControlled(IsSessile(), UNIT_STATE_ROOT);
if (IsSwimPrevented())
{
SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS);
SetSwim(false);
}
else
RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS);
UpdateMovementCapabilities();
}
void Creature::UpdateMovementCapabilities()
{
// Do not update movement flags if creature is controlled by a player (charm/vehicle)
if (IsMovedByClient())
return;
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
float ground = GetFloorZ();
bool isInAir = (G3D::fuzzyGt(GetPositionZ(), ground + GetHoverOffset() + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZ(), ground - GROUND_HEIGHT_TOLERANCE)); // Can be underground too, prevent the falling
if (!isInAir)
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS))
if (GetVictim() && GetVictim()->IsInWater() && !GetVictim()->IsOnOceanFloor())
RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS);
if (IsInWater() && CanSwim())
SetSwim(true);
else if (!IsInWater()) // We do not want to disable swimming again when a creature is in water - may to lead some nasty bugs
SetSwim(false);
}
CreatureMovementData const& Creature::GetMovementTemplate() const
{
if (CreatureMovementData const* movementOverride = sObjectMgr->GetCreatureMovementOverride(m_spawnId))
@@ -2691,25 +2704,6 @@ bool Creature::CanSwim() const
return false;
}
bool Creature::CanEnterWater() const
{
if (CanSwim())
return true;
return GetMovementTemplate().IsSwimAllowed();
}
void Creature::RefreshSwimmingFlag(bool recheck)
{
if (!_isMissingSwimmingFlagOutOfCombat || recheck)
_isMissingSwimmingFlagOutOfCombat = !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
// Check if the creature has UNIT_FLAG_SWIMMING and add it if it's missing
// Creatures must be able to chase a target in water if they can enter water
if (_isMissingSwimmingFlagOutOfCombat && CanEnterWater())
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
}
void Creature::InitializeCreatureMovementInfo(uint32 movementId)
{
if (CreatureMovementInfoOverride const* movementInfoOverride = sObjectMgr->GetCreatureMovementInfoOverride(movementId))
@@ -3001,56 +2995,6 @@ float Creature::GetNativeObjectScale() const
return GetCreatureTemplate()->scale;
}
void Creature::InitializeMovementFlags()
{
LoadTemplateRoot();
// It does the same, for now
UpdateMovementFlags(true);
}
void Creature::UpdateMovementFlags(bool initializeDBStates)
{
// Do not update movement flags if creature is controlled by a player (charm/vehicle)
if (IsMovedByClient())
return;
// Creatures with CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE should control MovementFlags in your own scripts
if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE)
return;
// These movement states are static and should only get applied when initializing a creature's entry (when spawning or transforming)
if (initializeDBStates)
{
if (GetMovementTemplate().IsFlightAllowed())
{
if (GetMovementTemplate().IsGravityDisabled())
SetDisableGravity(true);
if (GetMovementTemplate().CanFly())
SetCanFly(true);
}
if (GetMovementTemplate().IsGroundAllowed())
{
// Hovering always requires the creature to be alive to avoid visual issues. The IsAlive() check can be removed when respawn compatability has been removed.
// @todo: sniffed spawn locations have applied hover offsets to the position z value so either substract them when parsing sniffs or skip the initial relocation from Unit::SetHover
if (IsAlive() && GetMovementTemplate().IsHoverEnabled())
SetHover(true);
}
}
else
{
// These are realtime movement flag updates which are being updated per tick
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
float ground = GetFloorZ();
bool isInAir = (G3D::fuzzyGt(GetPositionZ(), ground + (IsHovering() ? GetFloatValue(UNIT_FIELD_HOVERHEIGHT) : 0.0f) + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZ(), ground - GROUND_HEIGHT_TOLERANCE)); // Can be underground too, prevent the falling
if (!isInAir)
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
}
SetSwim(CanSwim() && IsInWater());
}
void Creature::SetObjectScale(float scale)
{
Unit::SetObjectScale(scale);
@@ -3130,7 +3074,7 @@ void Creature::SetSpellFocus(Spell const* focusSpell, WorldObject const* target)
_spellFocusInfo.FocusSpell = focusSpell;
// Block target based focusing when the attributes or unit flags say so.
bool dontFaceTarget = spellInfo->HasAttribute(SPELL_ATTR5_AI_DOESNT_FACE_TARGET)|| spellInfo->HasAttribute(SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL) || HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN);
bool dontFaceTarget = spellInfo->HasAttribute(SPELL_ATTR5_AI_DOESNT_FACE_TARGET)|| spellInfo->HasAttribute(SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL) || HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CANNOT_TURN);
ObjectGuid newTarget = (dontFaceTarget || target == this || target == nullptr) ? ObjectGuid::Empty : target->GetGUID();
@@ -3185,7 +3129,7 @@ void Creature::ReleaseSpellFocus(Spell const* focusSpell, bool withDelay)
if (IsPet()) // player pets do not use delay system
{
if (!HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN))
if (!HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CANNOT_TURN))
ReacquireSpellFocusTarget();
}
else // don't allow re-target right away to prevent visual bugs
@@ -3204,7 +3148,7 @@ void Creature::ReacquireSpellFocusTarget()
SetGuidValue(UNIT_FIELD_TARGET, _spellFocusInfo.OriginalUnitTarget);
if (!HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN))
if (!HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CANNOT_TURN))
{
if (_spellFocusInfo.OriginalUnitTarget)
{
@@ -3284,8 +3228,6 @@ void Creature::AtEngage(Unit* target)
if (!(GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_MOUNTED_COMBAT_ALLOWED))
Dismount();
RefreshSwimmingFlag();
MovementGeneratorType const movetype = GetMotionMaster()->GetCurrentMovementGeneratorType();
if (movetype == WAYPOINT_MOTION_TYPE || movetype == CYCLIC_SPLINE_MOTION_TYPE || movetype == POINT_MOTION_TYPE || (IsAIEnabled() && AI()->IsEscorted()))
SetHomePosition(GetPosition());
+31 -16
View File
@@ -80,9 +80,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
void UpdateLevelDependantStats();
void LoadEquipment(int8 id = 1, bool force = false);
void SetSpawnHealth();
void LoadTemplateRoot();
bool IsTemplateRooted() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_SESSILE); }
void SetTemplateRooted(bool rooted);
ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
@@ -99,12 +96,39 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool IsTrigger() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) != 0; }
bool IsGuard() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_GUARD) != 0; }
void InitializeMovementCapabilities();
void UpdateMovementCapabilities();
CreatureMovementData const& GetMovementTemplate() const;
bool CanWalk() const { return GetMovementTemplate().IsGroundAllowed(); }
// Returns true if CREATURE_STATIC_FLAG_AQUATIC is set which strictly binds the creature to liquids
bool IsAquatic() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_AQUATIC); }
// Returns true if CREATURE_STATIC_FLAG_AMPHIBIOUS is set which allows a creature to enter and leave liquids while sticking to the ocean floor. These creatures will become able to swim when engaged
bool IsAmphibious() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_AMPHIBIOUS); }
// Returns true if CREATURE_STATIC_FLAG_FLOATING is set which is disabling the gravity of the creature on spawn and reset
bool IsFloating() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_FLOATING); }
void SetFloating(bool floating) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_FLOATING, floating); SetDisableGravity(floating); }
// Returns true if CREATURE_STATIC_FLAG_SESSILE is set which permanently roots the creature in place
bool IsSessile() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_SESSILE); }
void SetSessile(bool sessile) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_SESSILE, sessile); SetControlled(sessile, UNIT_STATE_ROOT); }
// Returns true if CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER is set which does not allow the creature to go below liquid surfaces
bool CannotPenetrateWater() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER); }
void SetCannotPenetrateWater(bool cannotPenetrateWater) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER, cannotPenetrateWater); }
// Returns true if CREATURE_STATIC_FLAG_3_CANNOT_SWIM is set which prevents 'Amphibious' creatures from swimming when engaged
bool IsSwimDisabled() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_SWIM); }
// Returns true if CREATURE_STATIC_FLAG_4_PREVENT_SWIM is set which prevents 'Amphibious' creatures from swimming when engaged until the victim is no longer on the ocean floor
bool IsSwimPrevented() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_PREVENT_SWIM); }
bool CanSwim() const override;
bool CanEnterWater() const override;
bool CanFly() const override { return GetMovementTemplate().IsFlightAllowed() || IsFlying(); }
bool CanHover() const { return GetMovementTemplate().IsHoverEnabled() || IsHovering(); }
bool CanEnterWater() const override { return (CanSwim() || IsAmphibious()); };
bool CanFly() const override { return (IsFlying() || HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY)); }
bool SetDisableGravity(bool disable, bool packetOnly = false, bool updateAnimationTier = true) override;
bool SetHover(bool enable, bool packetOnly = false, bool updateAnimationTier = true) override;
bool SetCanFly(bool enable, bool packetOnly = false) override;
@@ -166,9 +190,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr, bool updateLevel = true);
void InitializeMovementFlags();
void UpdateMovementFlags(bool initializeDBStates);
bool UpdateStats(Stats stat) override;
bool UpdateAllStats() override;
void UpdateResistances(uint32 school) override;
@@ -379,12 +400,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool HasStaticFlag(CreatureStaticFlags4 flag) const { return _staticFlags.HasFlag(flag); }
bool HasStaticFlag(CreatureStaticFlags5 flag) const { return _staticFlags.HasFlag(flag); }
bool HasSwimmingFlagOutOfCombat() const
{
return !_isMissingSwimmingFlagOutOfCombat;
}
void RefreshSwimmingFlag(bool recheck = false);
CreatureMovementInfo const& GetCreatureMovementInfo() const { return _creatureMovementInfo; }
// Sets the the max health percentage threshold at which uncontrolled/unowned creatures can no longer deal damage to the creature
@@ -45,7 +45,7 @@ enum CreatureFlagsExtra : uint32
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags
CREATURE_FLAG_EXTRA_UNUSED_9 = 0x00000200,
CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will be only visible for dead players
CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK = 0x00000800, // creature will use offhand attacks
CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor
@@ -296,24 +296,6 @@ private:
EnumFlag<CreatureStaticFlags5> _flags5;
};
enum class CreatureGroundMovementType : uint8
{
None,
Run,
Hover,
Max
};
enum class CreatureFlightMovementType : uint8
{
None,
DisableGravity,
CanFly,
Max
};
enum class CreatureRandomMovementType : uint8
{
Walk,
@@ -327,23 +309,14 @@ struct TC_GAME_API CreatureMovementData
{
CreatureMovementData();
CreatureGroundMovementType Ground;
CreatureFlightMovementType Flight;
bool Swim;
bool Rooted;
bool HoverInitiallyEnabled;
CreatureRandomMovementType Random;
uint32 InteractionPauseTimer;
bool IsGroundAllowed() const { return Ground != CreatureGroundMovementType::None; }
bool IsSwimAllowed() const { return Swim; }
bool IsFlightAllowed() const { return Flight != CreatureFlightMovementType::None; }
bool IsRooted() const { return Rooted; }
bool IsGravityDisabled() const { return Flight == CreatureFlightMovementType::DisableGravity; }
bool CanFly() const { return Flight == CreatureFlightMovementType::CanFly; }
bool IsHoverEnabled() const { return Ground == CreatureGroundMovementType::Hover; }
CreatureRandomMovementType GetRandom() const { return Random; }
bool IsHoverInitiallyEnabled() const { return HoverInitiallyEnabled; }
uint32 GetInteractionPauseTimer() const { return InteractionPauseTimer; }
std::string ToString() const;
+11 -3
View File
@@ -3710,9 +3710,17 @@ float WorldObject::GetFloorZ() const
float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const
{
return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground,
isType(TYPEMASK_UNIT) ? !static_cast<Unit const*>(this)->HasAuraType(SPELL_AURA_WATER_WALK) : false,
GetCollisionHeight());
bool swimming = [&]()
{
if (Creature const* creature = ToCreature())
return (!creature->CannotPenetrateWater() && !creature->HasAuraType(SPELL_AURA_WATER_WALK));
else if (Unit const* unit = ToUnit())
return !unit->HasAuraType(SPELL_AURA_WATER_WALK);
return true;
}();
return GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ground, swimming, GetCollisionHeight());
}
float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/, float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/) const
+30 -8
View File
@@ -2940,10 +2940,23 @@ bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
bool Unit::isInAccessiblePlaceFor(Creature const* c) const
{
if (IsInWater())
return c->CanEnterWater();
else
return c->CanWalk() || c->CanFly();
// Aquatic creatures are not allowed to leave liquids
if (!IsInWater() && c->IsAquatic())
return false;
// Underwater special case. Some creatures may not go below liquid surfaces
if (IsUnderWater() && c->CannotPenetrateWater())
return false;
// Water checks
if (IsInWater() && !c->CanEnterWater())
return false;
// Some creatures are tied to the ocean floor and cannot chase swimming targets.
if (!IsOnOceanFloor() && c->IsUnderWater() && c->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CANT_SWIM))
return false;
return true;
}
bool Unit::IsInWater() const
@@ -2956,6 +2969,11 @@ bool Unit::IsUnderWater() const
return GetLiquidStatus() & LIQUID_MAP_UNDER_WATER;
}
bool Unit::IsOnOceanFloor() const
{
return GetLiquidStatus() & LIQUID_MAP_OCEAN_FLOOR;
}
void Unit::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
{
ZLiquidStatus oldLiquidStatus = GetLiquidStatus();
@@ -8673,6 +8691,10 @@ void Unit::UpdatePetCombatState()
{
ASSERT(!IsPet()); // player pets do not use UNIT_FLAG_PET_IN_COMBAT for this purpose - but player pets should also never have minions of their own to call this
// UNIT_FLAG_PET_IN_COMBAT is set by default when the summoner is in combat by himself
if (IsInCombat())
return;
bool state = false;
for (Unit* minion : m_Controlled)
if (minion->IsInCombat())
@@ -11325,7 +11347,7 @@ void Unit::SetControlled(bool apply, UnitState state)
SetStunned(false);
break;
case UNIT_STATE_ROOT:
if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle() || (ToCreature() && ToCreature()->GetMovementTemplate().IsRooted()))
if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle() || (IsCreature() && ToCreature()->IsSessile()))
return;
ClearUnitState(state);
@@ -12972,15 +12994,15 @@ bool Unit::IsFalling() const
bool Unit::CanSwim() const
{
// Mirror client behavior, if this method returns false then client will not use swimming animation and for players will apply gravity as if there was no water
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CANNOT_SWIM))
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CANT_SWIM))
return false;
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)) // is player
return true;
if (HasFlag(UNIT_FIELD_FLAGS_2, 0x1000000))
if (HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS))
return false;
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT))
return true;
return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_RENAME | UNIT_FLAG_SWIMMING);
return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_RENAME | UNIT_FLAG_CAN_SWIM);
}
void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
+2 -4
View File
@@ -1124,6 +1124,7 @@ class TC_GAME_API Unit : public WorldObject
bool IsInWater() const;
bool IsUnderWater() const;
bool IsOnOceanFloor() const;
bool isInAccessiblePlaceFor(Creature const* c) const;
void SendHealSpellLog(HealInfo& healInfo, bool critical = false);
@@ -1715,10 +1716,7 @@ class TC_GAME_API Unit : public WorldObject
virtual bool CanEnterWater() const = 0;
virtual bool CanSwim() const;
float GetHoverOffset() const
{
return HasUnitMovementFlag(MOVEMENTFLAG_HOVER) ? GetFloatValue(UNIT_FIELD_HOVERHEIGHT) : 0.0f;
}
float GetHoverOffset() const { return HasUnitMovementFlag(MOVEMENTFLAG_HOVER) ? GetFloatValue(UNIT_FIELD_HOVERHEIGHT) : 0.0f; }
uint32 GetMovementCounterAndInc() { return m_movementCounter++; }
uint32 GetMovementCounter() { return m_movementCounter; }
+28 -23
View File
@@ -138,8 +138,8 @@ enum UnitFlags : uint32
UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // on player pets: whether the pet is chasing a target to attack || on other units: whether any of the unit's minions is in combat
UNIT_FLAG_PVP = 0x00001000, // changed in 3.0.3
UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1
UNIT_FLAG_CANNOT_SWIM = 0x00004000, // 2.0.8
UNIT_FLAG_SWIMMING = 0x00008000, // shows swim animation in water
UNIT_FLAG_CANT_SWIM = 0x00004000, // 2.0.8
UNIT_FLAG_CAN_SWIM = 0x00008000, // shows swim animation in water
UNIT_FLAG_NOT_ATTACKABLE_2 = 0x00010000,
UNIT_FLAG_PACIFIED = 0x00020000, // 3.0.3 ok
UNIT_FLAG_STUNNED = 0x00040000, // 3.0.3 ok
@@ -162,27 +162,32 @@ enum UnitFlags : uint32
// Value masks for UNIT_FIELD_FLAGS_2
enum UnitFlags2 : uint32
{
UNIT_FLAG2_FEIGN_DEATH = 0x00000001,
UNIT_FLAG2_UNK1 = 0x00000002, // Hide unit model (show only player equip)
UNIT_FLAG2_IGNORE_REPUTATION = 0x00000004,
UNIT_FLAG2_COMPREHEND_LANG = 0x00000008,
UNIT_FLAG2_MIRROR_IMAGE = 0x00000010,
UNIT_FLAG2_INSTANTLY_APPEAR_MODEL = 0x00000020, // Unit model instantly appears when summoned (does not fade in)
UNIT_FLAG2_FORCE_MOVEMENT = 0x00000040,
UNIT_FLAG2_DISARM_OFFHAND = 0x00000080,
UNIT_FLAG2_DISABLE_PRED_STATS = 0x00000100, // Player has disabled predicted stats (Used by raid frames)
UNIT_FLAG2_DISARM_RANGED = 0x00000400, // this does not disable ranged weapon display (maybe additional flag needed?)
UNIT_FLAG2_REGENERATE_POWER = 0x00000800,
UNIT_FLAG2_RESTRICT_PARTY_INTERACTION = 0x00001000, // Restrict interaction to party or raid
UNIT_FLAG2_PREVENT_SPELL_CLICK = 0x00002000, // Prevent spellclick
UNIT_FLAG2_ALLOW_ENEMY_INTERACT = 0x00004000,
UNIT_FLAG2_DISABLE_TURN = 0x00008000,
UNIT_FLAG2_UNK2 = 0x00010000,
UNIT_FLAG2_PLAY_DEATH_ANIM = 0x00020000, // Plays special death animation upon death
UNIT_FLAG2_ALLOW_CHEAT_SPELLS = 0x00040000, // Allows casting spells with AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL
UNIT_FLAG2_NO_ACTIONS = 0x00800000,
UNIT_FLAG2_DISABLE_UNIT_FRAME = 0x04000000, // Disables the unit frame when selecting the target
UNIT_FLAG2_IGNORE_SPELL_MIN_RANGE_RESTRICTIONS = 0x08000000 // Allows spells with a min range restriction to be cast when closer than given range value
UNIT_FLAG2_FEIGN_DEATH = 0x00000001,
UNIT_FLAG2_UNK1 = 0x00000002, // Hide unit model (show only player equip)
UNIT_FLAG2_IGNORE_REPUTATION = 0x00000004,
UNIT_FLAG2_COMPREHEND_LANG = 0x00000008,
UNIT_FLAG2_MIRROR_IMAGE = 0x00000010,
UNIT_FLAG2_INSTANTLY_APPEAR_MODEL = 0x00000020, // Unit model instantly appears when summoned (does not fade in)
UNIT_FLAG2_FORCE_MOVEMENT = 0x00000040,
UNIT_FLAG2_DISARM_OFFHAND = 0x00000080,
UNIT_FLAG2_DISABLE_PRED_STATS = 0x00000100, // Player has disabled predicted stats (Used by raid frames)
UNIT_FLAG2_DISARM_RANGED = 0x00000400, // this does not disable ranged weapon display (maybe additional flag needed?)
UNIT_FLAG2_REGENERATE_POWER = 0x00000800,
UNIT_FLAG2_RESTRICT_PARTY_INTERACTION = 0x00001000, // Restrict interaction to party or raid
UNIT_FLAG2_PREVENT_SPELL_CLICK = 0x00002000, // Prevent spellclick
UNIT_FLAG2_ALLOW_ENEMY_INTERACT = 0x00004000,
UNIT_FLAG2_CANNOT_TURN = 0x00008000,
UNIT_FLAG2_UNK2 = 0x00010000,
UNIT_FLAG2_PLAY_DEATH_ANIM = 0x00020000, // Plays special death animation upon death
UNIT_FLAG2_ALLOW_CHEAT_SPELLS = 0x00040000, // Allows casting spells with AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL
UNIT_FLAG2_SUPPRESS_HIGHLIGHT_WHEN_TARGETED_OR_MOUSED_OVER = 0x00080000, // Suppress highlight when targeted or moused over
UNIT_FLAG2_TREAT_AS_RAID_UNIT_FOR_HELPFUL_SPELLS = 0x00100000, // Treat as Raid Unit For Helpful Spells (Instances ONLY)
UNIT_FLAG2_LARGE_AOI = 0x00200000, // Large (AOI)
UNIT_FLAG2_GIGANTIC_AOI = 0x00400000, // Gigantic (AOI)
UNIT_FLAG2_NO_ACTIONS = 0x00800000,
UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS = 0x01000000, // AI will only swim if target swims
UNIT_FLAG2_DISABLE_UNIT_FRAME = 0x04000000, // Disables the unit frame when selecting the target
UNIT_FLAG2_IGNORE_SPELL_MIN_RANGE_RESTRICTIONS = 0x08000000 // Allows spells with a min range restriction to be cast when closer than given range value
};
/// Non Player Character flags
+44 -63
View File
@@ -433,11 +433,11 @@ void ObjectMgr::LoadCreatureTemplates()
"dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, "
// 48 49 50 51 52 53 54 55 56 57 58 59 60 61
"spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
// 62 63 64 65 66 67 68 69 70 71 72
"ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, "
// 73 74 75 76 77 78 79 80
// 62 63 64 65 66 67 68 69
"ctm.HoverInitiallyEnabled, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, "
// 70 71 72 73 74 75 76 77
"ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, "
// 81 82 83 84 85 86 87
// 78 79 80 81 82 83 84
"flags_extra, StaticFlags, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId");
if (!result)
@@ -528,41 +528,32 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields)
creatureTemplate.AIName = fields[60].GetString();
creatureTemplate.MovementType = uint32(fields[61].GetUInt8());
if (!fields[62].IsNull())
creatureTemplate.Movement.Ground = static_cast<CreatureGroundMovementType>(fields[62].GetUInt8());
creatureTemplate.Movement.HoverInitiallyEnabled = fields[62].GetBool();
if (!fields[63].IsNull())
creatureTemplate.Movement.Swim = fields[63].GetBool();
creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[63].GetUInt8());
if (!fields[64].IsNull())
creatureTemplate.Movement.Flight = static_cast<CreatureFlightMovementType>(fields[64].GetUInt8());
creatureTemplate.Movement.InteractionPauseTimer = fields[64].GetUInt32();
if (!fields[65].IsNull())
creatureTemplate.Movement.Rooted = fields[65].GetBool();
creatureTemplate.HoverHeight = fields[65].GetFloat();
creatureTemplate.ModHealth = fields[66].GetFloat();
creatureTemplate.ModHealthExtra = fields[67].GetFloat();
creatureTemplate.ModMana = fields[68].GetFloat();
creatureTemplate.ModManaExtra = fields[69].GetFloat();
creatureTemplate.ModArmor = fields[70].GetFloat();
creatureTemplate.ModDamage = fields[71].GetFloat();
creatureTemplate.ModExperience = fields[72].GetFloat();
if (!fields[66].IsNull())
creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[66].GetUInt8());
if (!fields[67].IsNull())
creatureTemplate.Movement.InteractionPauseTimer = fields[67].GetUInt32();
creatureTemplate.HoverHeight = fields[68].GetFloat();
creatureTemplate.ModHealth = fields[69].GetFloat();
creatureTemplate.ModHealthExtra = fields[70].GetFloat();
creatureTemplate.ModMana = fields[71].GetFloat();
creatureTemplate.ModManaExtra = fields[72].GetFloat();
creatureTemplate.ModArmor = fields[73].GetFloat();
creatureTemplate.ModDamage = fields[74].GetFloat();
creatureTemplate.ModExperience = fields[75].GetFloat();
creatureTemplate.RacialLeader = fields[76].GetBool();
creatureTemplate.movementId = fields[77].GetUInt32();
creatureTemplate.RegenHealth = fields[78].GetBool();
creatureTemplate.MechanicImmuneMask = fields[79].GetUInt32();
creatureTemplate.SpellSchoolImmuneMask = fields[80].GetUInt32();
creatureTemplate.flags_extra = fields[81].GetUInt32();
creatureTemplate.StaticFlags = CreatureStaticFlagsHolder(CreatureStaticFlags(fields[82].GetUInt32()), CreatureStaticFlags2(fields[83].GetUInt32()),
CreatureStaticFlags3(fields[84].GetUInt32()), CreatureStaticFlags4(fields[85].GetUInt32()), CreatureStaticFlags5(fields[86].GetUInt32()));
creatureTemplate.ScriptID = GetScriptId(fields[87].GetCString());
creatureTemplate.RacialLeader = fields[73].GetBool();
creatureTemplate.movementId = fields[74].GetUInt32();
creatureTemplate.RegenHealth = fields[75].GetBool();
creatureTemplate.MechanicImmuneMask = fields[76].GetUInt32();
creatureTemplate.SpellSchoolImmuneMask = fields[77].GetUInt32();
creatureTemplate.flags_extra = fields[78].GetUInt32();
creatureTemplate.StaticFlags = CreatureStaticFlagsHolder(CreatureStaticFlags(fields[79].GetUInt32()), CreatureStaticFlags2(fields[80].GetUInt32()),
CreatureStaticFlags3(fields[81].GetUInt32()), CreatureStaticFlags4(fields[82].GetUInt32()), CreatureStaticFlags5(fields[83].GetUInt32()));
creatureTemplate.ScriptID = GetScriptId(fields[84].GetCString());
}
void ObjectMgr::LoadCreatureTemplateModels()
@@ -757,7 +748,7 @@ void ObjectMgr::LoadCreatureSparringTemplate()
{
uint32 oldMSTime = getMSTime();
// 0 1
// 0 1
QueryResult result = WorldDatabase.Query("SELECT CreatureID, HealthLimitPct FROM creature_sparring_template");
if (!result)
@@ -1129,20 +1120,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
void ObjectMgr::CheckCreatureMovement(char const* table, uint64 id, CreatureMovementData& creatureMovement)
{
if (creatureMovement.Ground >= CreatureGroundMovementType::Max)
{
TC_LOG_ERROR("sql.sql", "`%s`.`Ground` wrong value (%u) for Id " UI64FMTD ", setting to Run.",
table, uint32(creatureMovement.Ground), id);
creatureMovement.Ground = CreatureGroundMovementType::Run;
}
if (creatureMovement.Flight >= CreatureFlightMovementType::Max)
{
TC_LOG_ERROR("sql.sql", "`%s`.`Flight` wrong value (%u) for Id " UI64FMTD ", setting to None.",
table, uint32(creatureMovement.Flight), id);
creatureMovement.Flight = CreatureFlightMovementType::None;
}
if (creatureMovement.Random >= CreatureRandomMovementType::Max)
{
TC_LOG_ERROR("sql.sql", "`%s`.`Random` wrong value (%u) for Id " UI64FMTD ", setting to Walk.",
@@ -1513,10 +1490,7 @@ void ObjectMgr::LoadCreatureMovementOverrides()
// Load the data from creature_movement_override and if NULL fallback to creature_template_movement
QueryResult result = WorldDatabase.Query(
"SELECT cmo.SpawnId,"
"COALESCE(cmo.Ground, ctm.Ground),"
"COALESCE(cmo.Swim, ctm.Swim),"
"COALESCE(cmo.Flight, ctm.Flight),"
"COALESCE(cmo.Rooted, ctm.Rooted),"
"COALESCE(cmo.HoverInitiallyEnabled, ctm.HoverInitiallyEnabled),"
"COALESCE(cmo.Random, ctm.Random),"
"COALESCE(cmo.InteractionPauseTimer, ctm.InteractionPauseTimer) "
"FROM creature_movement_override AS cmo "
@@ -1541,17 +1515,11 @@ void ObjectMgr::LoadCreatureMovementOverrides()
CreatureMovementData& movement = _creatureMovementOverrides[spawnId];
if (!fields[1].IsNull())
movement.Ground = static_cast<CreatureGroundMovementType>(fields[1].GetUInt8());
movement.HoverInitiallyEnabled = fields[1].GetBool();
if (!fields[2].IsNull())
movement.Swim = fields[2].GetBool();
movement.Random = static_cast<CreatureRandomMovementType>(fields[3].GetUInt8());
if (!fields[3].IsNull())
movement.Flight = static_cast<CreatureFlightMovementType>(fields[3].GetUInt8());
if (!fields[4].IsNull())
movement.Rooted = fields[4].GetBool();
if (!fields[5].IsNull())
movement.Random = static_cast<CreatureRandomMovementType>(fields[6].GetUInt8());
if (!fields[6].IsNull())
movement.InteractionPauseTimer = fields[6].GetUInt32();
movement.InteractionPauseTimer = fields[4].GetUInt32();
CheckCreatureMovement("creature_movement_override", spawnId, movement);
} while (result->NextRow());
@@ -1617,11 +1585,12 @@ CreatureModel const* ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, C
return cinfo->GetFirstInvisibleModel();
}
void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data /*= nullptr*/)
void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& unitFlags2, uint32& dynamicflags, CreatureStaticFlagsHolder const& staticFlags, CreatureData const* data /*= nullptr*/)
{
npcflag = cinfo->npcflag;
unit_flags = cinfo->unit_flags;
dynamicflags = cinfo->dynamicflags;
unitFlags2 = 0;
if (data)
{
@@ -1634,6 +1603,18 @@ void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcfl
if (data->dynamicflags)
dynamicflags = data->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;
}
CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(CreatureModel* model, CreatureTemplate const* creatureTemplate) const
@@ -10153,7 +10134,7 @@ void ObjectMgr::LoadTaxiNodeLevelData()
uint8 level = fields[1].GetUInt8();
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(taxiNodeId);
if (!node)
{
TC_LOG_ERROR("sql.sql", "Table `taxi_level_data` has data for nonexistent taxi node (ID: %u), skipped", taxiNodeId);
+2 -2
View File
@@ -851,7 +851,7 @@ struct QuestPOIWrapper
void InitializeQueryData();
ByteBuffer BuildQueryData() const;
QuestPOIWrapper() : QueryDataBuffer(0) { }
};
@@ -1015,7 +1015,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& dynamicflags, 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);
EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id) const;
CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid) const;
GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid) const;
+19 -11
View File
@@ -599,6 +599,8 @@ float GridMap::getLiquidLevel(float x, float y) const
return _liquidMap[cx_int*_liquidWidth + cy_int];
}
constexpr float GROUND_LEVEL_OFFSET_HACK = 0.02f; // due to floating point precision issues, we have to resort to a small hack to fix inconsistencies in liquids
// Get water state on map
ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, Optional<map_liquidHeaderTypeFlags> ReqLiquidType, LiquidData* data, float collisionHeight) const
{
@@ -661,12 +663,12 @@ ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, Optional<map_l
return LIQUID_MAP_NO_WATER;
// Get water level
float liquid_level = _liquidMap ? _liquidMap[lx_int*_liquidWidth + ly_int] : _liquidLevel;
// Get ground level (sub 0.2 for fix some errors)
float liquid_level = _liquidMap ? _liquidMap[lx_int * _liquidWidth + ly_int] : _liquidLevel;
// Get ground level (sub 0.02 for fix some errors)
float ground_level = getHeight(x, y);
// Check water level and ground level
if (liquid_level < ground_level || z < ground_level)
if (liquid_level < (ground_level - GROUND_LEVEL_OFFSET_HACK) || z < (ground_level - GROUND_LEVEL_OFFSET_HACK))
return LIQUID_MAP_NO_WATER;
// All ok in water -> store data
@@ -681,12 +683,18 @@ ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, Optional<map_l
// For speed check as int values
float delta = liquid_level - z;
if (delta > collisionHeight) // Under water
return LIQUID_MAP_UNDER_WATER;
if (delta > 0.0f) // In water
return LIQUID_MAP_IN_WATER;
if (delta > -0.1f) // Walk on water
return LIQUID_MAP_WATER_WALK;
// Above water
return LIQUID_MAP_ABOVE_WATER;
uint32 status = LIQUID_MAP_ABOVE_WATER; // Above water
if (delta > collisionHeight) // Under water
status = LIQUID_MAP_UNDER_WATER;
else if (delta > 0.0f) // In water
status = LIQUID_MAP_IN_WATER;
else if (delta > -0.1f) // Walk on water
status = LIQUID_MAP_WATER_WALK;
if (status != LIQUID_MAP_ABOVE_WATER)
if (std::fabs(ground_level - z) <= GROUND_HEIGHT_TOLERANCE)
status |= LIQUID_MAP_OCEAN_FLOOR;
return static_cast<ZLiquidStatus>(status);
}
+27 -11
View File
@@ -431,14 +431,19 @@ void TerrainInfo::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift,
data.liquidInfo->type_flags = map_liquidHeaderTypeFlags(1 << liquidFlagType);
float delta = wmoData->liquidInfo->level - z;
uint32 status = LIQUID_MAP_ABOVE_WATER;
if (delta > collisionHeight)
data.liquidStatus = LIQUID_MAP_UNDER_WATER;
status = LIQUID_MAP_UNDER_WATER;
else if (delta > 0.0f)
data.liquidStatus = LIQUID_MAP_IN_WATER;
status = LIQUID_MAP_IN_WATER;
else if (delta > -0.1f)
data.liquidStatus = LIQUID_MAP_WATER_WALK;
else
data.liquidStatus = LIQUID_MAP_ABOVE_WATER;
status = LIQUID_MAP_WATER_WALK;
if (status != LIQUID_MAP_ABOVE_WATER)
if (std::fabs(wmoData->floorZ - z) <= GROUND_HEIGHT_TOLERANCE)
status |= LIQUID_MAP_OCEAN_FLOOR;
data.liquidStatus = static_cast<ZLiquidStatus>(status);
}
// look up liquid data from grid map
if (gmap && useGridLiquid)
@@ -513,12 +518,23 @@ ZLiquidStatus TerrainInfo::GetLiquidStatus(PhaseShift const& phaseShift, uint32
float delta = liquid_level - z;
// Get position delta
if (delta > collisionHeight) // Under water
return LIQUID_MAP_UNDER_WATER;
if (delta > 0.0f) // In water
return LIQUID_MAP_IN_WATER;
if (delta > -0.1f) // Walk on water
return LIQUID_MAP_WATER_WALK;
uint32 status = LIQUID_MAP_ABOVE_WATER;
if (delta > collisionHeight) // Under water
status = LIQUID_MAP_UNDER_WATER;
else if (delta > 0.0f) // In water
status = LIQUID_MAP_IN_WATER;
else if (delta > -0.1f) // Walk on water
status = LIQUID_MAP_WATER_WALK;
if (status != LIQUID_MAP_ABOVE_WATER)
{
if (status != LIQUID_MAP_ABOVE_WATER)
if (std::fabs(ground_level - z) <= GROUND_HEIGHT_TOLERANCE)
status |= LIQUID_MAP_OCEAN_FLOOR;
return static_cast<ZLiquidStatus>(status);
}
result = LIQUID_MAP_ABOVE_WATER;
}
}
@@ -81,12 +81,9 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
if (_arrived)
{
if (!owner->HasSwimmingFlagOutOfCombat())
owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
owner->ClearUnitState(UNIT_STATE_EVADE);
owner->SetWalk(true);
owner->UpdateMovementFlags(true);
owner->InitializeMovementCapabilities();
owner->LoadCreaturesAddon();
if (owner->IsVehicle())
owner->GetVehicleKit()->Reset(true);
+3 -3
View File
@@ -191,7 +191,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
BuildShortcut();
bool path = _source->GetTypeId() == TYPEID_UNIT && _source->ToCreature()->CanFly();
bool waterPath = _source->GetTypeId() == TYPEID_UNIT && _source->ToCreature()->CanSwim();
bool waterPath = _source->GetTypeId() == TYPEID_UNIT && _source->ToCreature()->CanEnterWater();
if (waterPath)
{
// Check both start and end points, if they're both in water, then we can *safely* let the creature move
@@ -670,7 +670,7 @@ void PathGenerator::CreateFilter()
if (_source->GetTypeId() == TYPEID_UNIT)
{
Creature* creature = (Creature*)_source;
if (creature->CanWalk())
if (!creature->IsAquatic())
includeFlags |= NAV_GROUND; // walk
// creatures don't take environmental damage
@@ -696,7 +696,7 @@ void PathGenerator::UpdateFilter()
// allow creatures to cheat and use different movement types if they are moved
// forcefully into terrain they can't normally move in
if (const Unit* _sourceUnit = _source->ToUnit())
if (Unit const* _sourceUnit = _source->ToUnit())
{
if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
{
+3 -3
View File
@@ -135,8 +135,8 @@ EnumName<UnitFlags> const unitFlags[MAX_UNIT_FLAGS] =
CREATE_NAMED_ENUM(UNIT_FLAG_PET_IN_COMBAT),
CREATE_NAMED_ENUM(UNIT_FLAG_PVP),
CREATE_NAMED_ENUM(UNIT_FLAG_SILENCED),
CREATE_NAMED_ENUM(UNIT_FLAG_CANNOT_SWIM),
CREATE_NAMED_ENUM(UNIT_FLAG_SWIMMING),
CREATE_NAMED_ENUM(UNIT_FLAG_CANT_SWIM),
CREATE_NAMED_ENUM(UNIT_FLAG_CAN_SWIM),
CREATE_NAMED_ENUM(UNIT_FLAG_NOT_ATTACKABLE_2),
CREATE_NAMED_ENUM(UNIT_FLAG_PACIFIED),
CREATE_NAMED_ENUM(UNIT_FLAG_STUNNED),
@@ -166,7 +166,7 @@ EnumName<CreatureFlagsExtra> const flagsExtra[] =
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_UNUSED_9),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_SELL_VENDOR),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_COMBAT),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT),
@@ -536,7 +536,7 @@ public:
me->RestoreFaction();
CombatAI::Reset();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CAN_SWIM);
}
void SpellHit(WorldObject* pCaster, SpellInfo const* pSpell) override
@@ -631,7 +631,7 @@ public:
}
me->SetImmuneToPC(false);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CAN_SWIM);
player->CastSpell(me, SPELL_DUEL, false);
player->CastSpell(player, SPELL_DUEL_FLAG, true);
@@ -348,7 +348,7 @@ class npc_shard_of_torment : public CreatureScript
{
me->SetReactState(REACT_PASSIVE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN);
me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CANNOT_TURN);
me->SetDisplayFromModel(1);
_instance = creature->GetInstanceScript();
}
@@ -282,10 +282,10 @@ class spell_varos_centrifuge_shield : public SpellScriptLoader
if (Unit* caster = GetCaster())
{
// flags taken from sniffs
if (caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_UNK_6))
if (caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CAN_SWIM | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_UNK_6))
{
caster->ToCreature()->SetReactState(REACT_PASSIVE);
caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING | UNIT_FLAG_UNK_6);
caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CAN_SWIM | UNIT_FLAG_UNK_6);
caster->SetImmuneToAll(true, true);
}
}
@@ -296,7 +296,7 @@ class spell_varos_centrifuge_shield : public SpellScriptLoader
if (Unit* caster = GetCaster())
{
caster->ToCreature()->SetReactState(REACT_AGGRESSIVE);
caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING | UNIT_FLAG_UNK_6);
caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CAN_SWIM | UNIT_FLAG_UNK_6);
caster->SetImmuneToAll(false);
}
}