refactor(Core/Creature): Remove Inhabit Type (#9272)
This is in reference to issue: https://github.com/azerothcore/azerothcore-wotlk/issues/4361 This is comprised of a cherry pick and partial tc cherry pick:592516ae69dbadb6369c34cfa69efd12de860b4aa22bc236eb
This commit is contained in:
parent
d504a62293
commit
2d4e17fd16
26 changed files with 4948 additions and 230 deletions
4423
data/sql/updates/pending_db_world/rev_1637692848290406800.sql
Normal file
4423
data/sql/updates/pending_db_world/rev_1637692848290406800.sql
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -77,7 +77,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, security, 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, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, detection_range, scale, `rank`, dmgschool, DamageModifier, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template 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, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, detection_range, scale, `rank`, dmgschool, DamageModifier, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, 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_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH);
|
||||
|
|
|
|||
|
|
@ -94,6 +94,19 @@ void HostileRefMgr::setOnlineOfflineState(bool isOnline)
|
|||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// The online / offline status is calculated and set
|
||||
|
||||
void HostileRefMgr::updateThreatTables()
|
||||
{
|
||||
HostileReference* ref = getFirst();
|
||||
while (ref)
|
||||
{
|
||||
ref->updateOnlineStatus();
|
||||
ref = ref->next();
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================
|
||||
// The references are not needed anymore
|
||||
// tell the source to remove them from the list and free the mem
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ public:
|
|||
|
||||
HostileReference* getFirst() { return ((HostileReference*) RefMgr<Unit, ThreatMgr>::getFirst()); }
|
||||
|
||||
void updateThreatTables();
|
||||
|
||||
void setOnlineOfflineState(bool isOnline);
|
||||
|
||||
// set state for one reference, defined by Unit
|
||||
|
|
|
|||
|
|
@ -55,6 +55,31 @@
|
|||
// see: https://github.com/azerothcore/azerothcore-wotlk/issues/9766
|
||||
#include "GridNotifiersImpl.h"
|
||||
|
||||
CreatureMovementData::CreatureMovementData() : Ground(CreatureGroundMovementType::Run), Flight(CreatureFlightMovementType::None),
|
||||
Swim(true), Rooted(false), Chase(CreatureChaseMovementType::Run),
|
||||
Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) {}
|
||||
|
||||
std::string CreatureMovementData::ToString() const
|
||||
{
|
||||
constexpr std::array<char const*, 3> GroundStates = {"None", "Run", "Hover"};
|
||||
constexpr std::array<char const*, 3> FlightStates = {"None", "DisableGravity", "CanFly"};
|
||||
constexpr std::array<char const*, 3> ChaseStates = {"Run", "CanWalk", "AlwaysWalk"};
|
||||
constexpr std::array<char const*, 3> RandomStates = {"Walk", "CanRun", "AlwaysRun"};
|
||||
|
||||
std::ostringstream str;
|
||||
str << std::boolalpha
|
||||
<< "Ground: " << GroundStates[AsUnderlyingType(Ground)]
|
||||
<< ", Swim: " << Swim
|
||||
<< ", Flight: " << FlightStates[AsUnderlyingType(Flight)]
|
||||
<< ", Chase: " << ChaseStates[AsUnderlyingType(Chase)]
|
||||
<< ", Random: " << RandomStates[AsUnderlyingType(Random)];
|
||||
if (Rooted)
|
||||
str << ", Rooted";
|
||||
str << ", InteractionPauseTimer: " << InteractionPauseTimer;
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const
|
||||
{
|
||||
TrainerSpellMap::const_iterator itr = spellList.find(spell_id);
|
||||
|
|
@ -541,7 +566,7 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
|||
ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_ATTACK_ME, true);
|
||||
}
|
||||
|
||||
if (cInfo->InhabitType & INHABIT_ROOT)
|
||||
if (GetMovementTemplate().IsRooted())
|
||||
{
|
||||
SetControlled(true, UNIT_STATE_ROOT);
|
||||
}
|
||||
|
|
@ -2452,7 +2477,7 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool skipDistCheck) const
|
|||
else
|
||||
{
|
||||
// to prevent creatures in air ignore attacks because distance is already too high...
|
||||
if (GetCreatureTemplate()->InhabitType & INHABIT_AIR)
|
||||
if (GetMovementTemplate().IsFlightAllowed())
|
||||
return victim->IsInDist2d(&m_homePosition, dist);
|
||||
else
|
||||
return victim->IsInDist(&m_homePosition, dist);
|
||||
|
|
@ -2500,7 +2525,7 @@ bool Creature::LoadCreaturesAddon(bool reload)
|
|||
//! 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 (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_HOVER /*&& !(GetCreatureTemplate()->InhabitType & INHABIT_AIR)*/)
|
||||
if (CanHover())
|
||||
AddUnitMovementFlag(MOVEMENTFLAG_HOVER);
|
||||
}
|
||||
|
||||
|
|
@ -2731,6 +2756,14 @@ void Creature::GetRespawnPosition(float& x, float& y, float& z, float* ori, floa
|
|||
*dist = 0;
|
||||
}
|
||||
|
||||
CreatureMovementData const& Creature::GetMovementTemplate() const
|
||||
{
|
||||
if (CreatureMovementData const* movementOverride = sObjectMgr->GetCreatureMovementOverride(m_spawnId))
|
||||
return *movementOverride;
|
||||
|
||||
return GetCreatureTemplate()->Movement;
|
||||
}
|
||||
|
||||
void Creature::AllLootRemovedFromCorpse()
|
||||
{
|
||||
if (loot.loot_type != LOOT_SKINNING && !IsPet() && GetCreatureTemplate()->SkinLootId && hasLootRecipient())
|
||||
|
|
@ -2937,8 +2970,6 @@ bool Creature::SetDisableGravity(bool disable, bool packetOnly/*=false*/)
|
|||
if (!packetOnly && !Unit::SetDisableGravity(disable))
|
||||
return false;
|
||||
|
||||
applyInhabitFlags();
|
||||
|
||||
if (m_movedByPlayer)
|
||||
{
|
||||
WorldPacket data(disable ? SMSG_MOVE_GRAVITY_DISABLE : SMSG_MOVE_GRAVITY_ENABLE, 12);
|
||||
|
|
@ -2962,23 +2993,6 @@ bool Creature::SetDisableGravity(bool disable, bool packetOnly/*=false*/)
|
|||
return true;
|
||||
}
|
||||
|
||||
void Creature::applyInhabitFlags()
|
||||
{
|
||||
if (IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !HasUnitMovementFlag(MOVEMENTFLAG_ROOT))
|
||||
{
|
||||
if (IsLevitating())
|
||||
{
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
|
||||
}
|
||||
else if (IsHovering())
|
||||
{
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_HOVER);
|
||||
}
|
||||
else
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_GROUND);
|
||||
}
|
||||
}
|
||||
|
||||
bool Creature::SetSwim(bool enable)
|
||||
{
|
||||
if (!Unit::SetSwim(enable))
|
||||
|
|
@ -3016,7 +3030,7 @@ bool Creature::CanEnterWater() const
|
|||
if (CanSwim())
|
||||
return true;
|
||||
|
||||
return GetCreatureTemplate()->InhabitType & INHABIT_WATER;
|
||||
return GetMovementTemplate().IsSwimAllowed();
|
||||
}
|
||||
|
||||
void Creature::RefreshSwimmingFlag(bool recheck)
|
||||
|
|
@ -3063,14 +3077,6 @@ bool Creature::SetCanFly(bool enable, bool /*packetOnly*/ /* = false */)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Creature::CanFly() const
|
||||
{
|
||||
if (Unit::IsFlying())
|
||||
return true;
|
||||
|
||||
return GetCreatureTemplate()->InhabitType & INHABIT_AIR;
|
||||
}
|
||||
|
||||
bool Creature::SetWaterWalking(bool enable, bool packetOnly /* = false */)
|
||||
{
|
||||
if (!packetOnly && !Unit::SetWaterWalking(enable))
|
||||
|
|
@ -3132,22 +3138,6 @@ bool Creature::SetHover(bool enable, bool packetOnly /*= false*/)
|
|||
if (!packetOnly && !Unit::SetHover(enable))
|
||||
return false;
|
||||
|
||||
applyInhabitFlags();
|
||||
|
||||
if (m_movedByPlayer)
|
||||
{
|
||||
WorldPacket data(enable ? SMSG_MOVE_SET_HOVER : SMSG_MOVE_UNSET_HOVER, 12);
|
||||
data << GetPackGUID();
|
||||
data << uint32(0); //! movement counter
|
||||
m_movedByPlayer->ToPlayer()->SendDirectMessage(&data);
|
||||
|
||||
data.Initialize(MSG_MOVE_HOVER, 64);
|
||||
data << GetPackGUID();
|
||||
BuildMovementPacket(&data);
|
||||
m_movedByPlayer->ToPlayer()->SendMessageToSet(&data, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!movespline->Initialized())
|
||||
return true;
|
||||
|
||||
|
|
@ -3217,76 +3207,33 @@ void Creature::UpdateMovementFlags()
|
|||
if (info->flags_extra & CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE)
|
||||
return;
|
||||
|
||||
float z = GetPositionZ();
|
||||
float ground = GetFloorZ();
|
||||
|
||||
bool isInAir = false;
|
||||
bool Swim = false;
|
||||
|
||||
bool canHover = CanHover();
|
||||
bool isInAir = (G3D::fuzzyGt(GetPositionZ(), ground + (canHover ? GetFloatValue(UNIT_FIELD_HOVERHEIGHT) : 0.0f) + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZ(), ground - GROUND_HEIGHT_TOLERANCE)); // Can be underground too, prevent the falling
|
||||
|
||||
LiquidData const& liquidData = GetLiquidData();
|
||||
if (liquidData.Status == LIQUID_MAP_NO_WATER)
|
||||
if (GetMovementTemplate().IsFlightAllowed() && isInAir && !IsFalling())
|
||||
{
|
||||
if (ground > INVALID_HEIGHT)
|
||||
isInAir = G3D::fuzzyGt(z, ground + (canHover ? GetFloatValue(UNIT_FIELD_HOVERHEIGHT) : 0.0f) + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(z, ground - GROUND_HEIGHT_TOLERANCE); // Can be underground too, prevent the falling
|
||||
if (GetMovementTemplate().Flight == CreatureFlightMovementType::CanFly)
|
||||
SetCanFly(true);
|
||||
else
|
||||
isInAir = true;
|
||||
SetDisableGravity(true);
|
||||
|
||||
if (!HasAuraType(SPELL_AURA_HOVER))
|
||||
SetHover(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (liquidData.Status)
|
||||
{
|
||||
case LIQUID_MAP_ABOVE_WATER:
|
||||
isInAir = true;
|
||||
break;
|
||||
case LIQUID_MAP_WATER_WALK:
|
||||
isInAir = true;
|
||||
[[fallthrough]];
|
||||
case LIQUID_MAP_IN_WATER:
|
||||
Swim = z - liquidData.DepthLevel > GetCollisionHeight() * 0.75f; // Shallow water at ~75% of collision height
|
||||
break;
|
||||
case LIQUID_MAP_UNDER_WATER:
|
||||
Swim = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SetCanFly(false);
|
||||
SetDisableGravity(false);
|
||||
if (IsAlive() && (CanHover() || HasAuraType(SPELL_AURA_HOVER)))
|
||||
SetHover(true);
|
||||
}
|
||||
|
||||
SetSwim(CanSwim() && Swim);
|
||||
if (!isInAir)
|
||||
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
||||
|
||||
if (info->InhabitType & INHABIT_AIR)
|
||||
{
|
||||
if (isInAir && !IsFalling())
|
||||
{
|
||||
if (info->InhabitType & INHABIT_GROUND)
|
||||
{
|
||||
SetCanFly(true);
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
|
||||
}
|
||||
else
|
||||
SetDisableGravity(true);
|
||||
|
||||
if (!HasAuraType(SPELL_AURA_HOVER))
|
||||
SetHover(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCanFly(false);
|
||||
SetDisableGravity(false);
|
||||
|
||||
if (info->InhabitType & INHABIT_GROUND)
|
||||
{
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_GROUND);
|
||||
}
|
||||
|
||||
if (IsAlive() && (CanHover() || HasAuraType(SPELL_AURA_HOVER)))
|
||||
SetHover(true);
|
||||
}
|
||||
}
|
||||
else if (!HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY) && IsAlive() && (CanHover() || HasAuraType(SPELL_AURA_HOVER)))
|
||||
SetHover(true);
|
||||
SetSwim(CanSwim() && IsInWater());
|
||||
}
|
||||
|
||||
void Creature::SetObjectScale(float scale)
|
||||
|
|
|
|||
|
|
@ -74,11 +74,15 @@ public:
|
|||
[[nodiscard]] bool IsCivilian() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN; }
|
||||
[[nodiscard]] bool IsTrigger() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER; }
|
||||
[[nodiscard]] bool IsGuard() const { return GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_GUARD; }
|
||||
[[nodiscard]] bool CanWalk() const { return GetCreatureTemplate()->InhabitType & INHABIT_GROUND; }
|
||||
CreatureMovementData const& GetMovementTemplate() const;
|
||||
[[nodiscard]] bool CanWalk() const { return GetMovementTemplate().IsGroundAllowed(); }
|
||||
[[nodiscard]] bool CanSwim() const override;
|
||||
[[nodiscard]] bool CanEnterWater() const override;
|
||||
[[nodiscard]] bool CanFly() const override;
|
||||
[[nodiscard]] bool CanHover() const { return m_originalAnimTier & UNIT_BYTE1_FLAG_HOVER || IsHovering(); }
|
||||
[[nodiscard]] bool CanFly() const override { return GetMovementTemplate().IsFlightAllowed() || IsFlying(); }
|
||||
[[nodiscard]] bool CanHover() const { return GetMovementTemplate().Ground == CreatureGroundMovementType::Hover || IsHovering(); }
|
||||
|
||||
MovementGeneratorType GetDefaultMovementType() const override { return m_defaultMovementType; }
|
||||
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
|
||||
|
||||
void SetReactState(ReactStates st) { m_reactState = st; }
|
||||
[[nodiscard]] ReactStates GetReactState() const { return m_reactState; }
|
||||
|
|
@ -261,9 +265,6 @@ public:
|
|||
bool IsMoveInLineOfSightDisabled() { return m_moveInLineOfSightDisabled; }
|
||||
bool IsMoveInLineOfSightStrictlyDisabled() { return m_moveInLineOfSightStrictlyDisabled; }
|
||||
|
||||
[[nodiscard]] MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
|
||||
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
|
||||
|
||||
void RemoveCorpse(bool setSpawnTime = true, bool skipVisibility = false);
|
||||
|
||||
void DespawnOrUnsummon(Milliseconds msTimeToDespawn, Seconds forcedRespawnTimer);
|
||||
|
|
@ -462,7 +463,6 @@ private:
|
|||
|
||||
uint32 m_assistanceTimer;
|
||||
|
||||
void applyInhabitFlags();
|
||||
};
|
||||
|
||||
class AssistDelayEvent : public BasicEvent
|
||||
|
|
|
|||
|
|
@ -86,6 +86,92 @@ enum CreatureFlagsExtra : uint32
|
|||
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP
|
||||
};
|
||||
|
||||
enum class CreatureGroundMovementType : uint8
|
||||
{
|
||||
None,
|
||||
Run,
|
||||
Hover,
|
||||
|
||||
Max
|
||||
};
|
||||
|
||||
enum class CreatureFlightMovementType : uint8
|
||||
{
|
||||
None,
|
||||
DisableGravity,
|
||||
CanFly,
|
||||
|
||||
Max
|
||||
};
|
||||
|
||||
enum class CreatureChaseMovementType : uint8
|
||||
{
|
||||
Run,
|
||||
CanWalk,
|
||||
AlwaysWalk,
|
||||
|
||||
Max
|
||||
};
|
||||
|
||||
enum class CreatureRandomMovementType : uint8
|
||||
{
|
||||
Walk,
|
||||
CanRun,
|
||||
AlwaysRun,
|
||||
|
||||
Max
|
||||
};
|
||||
|
||||
struct CreatureMovementData
|
||||
{
|
||||
CreatureMovementData();
|
||||
|
||||
CreatureGroundMovementType Ground;
|
||||
CreatureFlightMovementType Flight;
|
||||
bool Swim;
|
||||
bool Rooted;
|
||||
CreatureChaseMovementType Chase;
|
||||
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;
|
||||
}
|
||||
|
||||
CreatureChaseMovementType GetChase() const
|
||||
{
|
||||
return Chase;
|
||||
}
|
||||
|
||||
CreatureRandomMovementType GetRandom() const
|
||||
{
|
||||
return Random;
|
||||
}
|
||||
|
||||
uint32 GetInteractionPauseTimer() const
|
||||
{
|
||||
return InteractionPauseTimer;
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
// from `creature_template` table
|
||||
struct CreatureTemplate
|
||||
{
|
||||
|
|
@ -138,7 +224,7 @@ struct CreatureTemplate
|
|||
uint32 maxgold;
|
||||
std::string AIName;
|
||||
uint32 MovementType;
|
||||
uint32 InhabitType;
|
||||
CreatureMovementData Movement;
|
||||
float HoverHeight;
|
||||
float ModHealth;
|
||||
float ModMana;
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
|||
|
||||
m_MirrorTimerFlags = UNDERWATER_NONE;
|
||||
m_MirrorTimerFlagsLast = UNDERWATER_NONE;
|
||||
m_isInWater = false;
|
||||
m_drunkTimer = 0;
|
||||
m_deathTimer = 0;
|
||||
m_deathExpireTime = 0;
|
||||
|
|
@ -2087,6 +2088,24 @@ bool Player::IsFalling() const
|
|||
return GetPositionZ() < m_lastFallZ && !IsInFlight();
|
||||
}
|
||||
|
||||
void Player::SetInWater(bool apply)
|
||||
{
|
||||
if (m_isInWater == apply)
|
||||
return;
|
||||
|
||||
//define player in water by opcodes
|
||||
//move player's guid into HateOfflineList of those mobs
|
||||
//which can't swim and move guid back into ThreatList when
|
||||
//on surface.
|
||||
//TODO: exist also swimming mobs, and function must be symmetric to enter/leave water
|
||||
m_isInWater = apply;
|
||||
|
||||
// remove auras that need water/land
|
||||
RemoveAurasWithInterruptFlags(apply ? AURA_INTERRUPT_FLAG_NOT_ABOVEWATER : AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
|
||||
|
||||
getHostileRefMgr().updateThreatTables();
|
||||
}
|
||||
|
||||
bool Player::IsInAreaTriggerRadius(const AreaTrigger* trigger) const
|
||||
{
|
||||
static const float delta = 5.0f;
|
||||
|
|
|
|||
|
|
@ -1086,6 +1086,9 @@ public:
|
|||
|
||||
static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data);
|
||||
|
||||
void SetInWater(bool apply);
|
||||
|
||||
[[nodiscard]] bool IsInWater() const override { return m_isInWater; }
|
||||
[[nodiscard]] bool IsFalling() const;
|
||||
bool IsInAreaTriggerRadius(const AreaTrigger* trigger) const;
|
||||
|
||||
|
|
@ -2915,6 +2918,7 @@ private:
|
|||
int32 m_MirrorTimer[MAX_TIMERS];
|
||||
uint8 m_MirrorTimerFlags;
|
||||
uint8 m_MirrorTimerFlagsLast;
|
||||
bool m_isInWater;
|
||||
|
||||
// Current teleport data
|
||||
WorldLocation teleportStore_dest;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "InstanceScript.h"
|
||||
#include "Log.h"
|
||||
#include "MapMgr.h"
|
||||
#include "MovementGenerator.h"
|
||||
#include "MoveSpline.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "ObjectAccessor.h"
|
||||
|
|
@ -3777,13 +3778,14 @@ bool Unit::isInAccessiblePlaceFor(Creature const* c) const
|
|||
return false;
|
||||
}
|
||||
|
||||
// In water or jumping in water
|
||||
if (IsInWater() || (GetLiquidData().Status == LIQUID_MAP_ABOVE_WATER && (IsFalling() || (ToPlayer() && ToPlayer()->IsFalling()))))
|
||||
if (IsInWater())
|
||||
{
|
||||
return IsUnderWater() ? c->CanEnterWater() : (c->CanEnterWater() || c->CanFly());
|
||||
return c->CanEnterWater();
|
||||
}
|
||||
else
|
||||
{
|
||||
return c->CanWalk() || c->CanFly();
|
||||
}
|
||||
|
||||
return c->CanWalk() || c->CanFly() || (c->CanSwim() && IsInWater());
|
||||
}
|
||||
|
||||
void Unit::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
||||
|
|
@ -13578,28 +13580,29 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
|
|||
case MOVE_RUN:
|
||||
case MOVE_SWIM:
|
||||
case MOVE_FLIGHT:
|
||||
{
|
||||
// Set creature speed rate
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
|
||||
|
||||
// Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
|
||||
/// @todo possible affect only on MOVE_RUN
|
||||
if (int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED))
|
||||
{
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
if (Creature* creature = ToCreature())
|
||||
{
|
||||
speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
|
||||
uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask;
|
||||
if (immuneMask & (1 << (MECHANIC_SNARE - 1)) || immuneMask & (1 << (MECHANIC_DAZE - 1)))
|
||||
break;
|
||||
}
|
||||
|
||||
// Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
|
||||
// TODO: possible affect only on MOVE_RUN
|
||||
if (int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED))
|
||||
{
|
||||
// Use speed from aura
|
||||
float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
|
||||
|
||||
// Xinef: normal movement speed - multiply by creature db modifer
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
max_speed *= ToCreature()->GetCreatureTemplate()->speed_run;
|
||||
|
||||
if (speed > max_speed)
|
||||
speed = max_speed;
|
||||
}
|
||||
break;
|
||||
// Use speed from aura
|
||||
float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
|
||||
if (speed > max_speed)
|
||||
speed = max_speed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -16039,6 +16042,11 @@ void Unit::SendPetAIReaction(ObjectGuid guid)
|
|||
|
||||
///----------End of Pet responses methods----------
|
||||
|
||||
MovementGeneratorType Unit::GetDefaultMovementType() const
|
||||
{
|
||||
return IDLE_MOTION_TYPE;
|
||||
}
|
||||
|
||||
void Unit::StopMoving()
|
||||
{
|
||||
ClearUnitState(UNIT_STATE_MOVING);
|
||||
|
|
@ -16058,6 +16066,26 @@ void Unit::StopMoving()
|
|||
init.Stop();
|
||||
}
|
||||
|
||||
void Unit::PauseMovement(uint32 timer /* = 0*/, uint8 slot /* = 0*/)
|
||||
{
|
||||
if (slot >= MAX_MOTION_SLOT)
|
||||
return;
|
||||
|
||||
if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(slot))
|
||||
movementGenerator->Pause(timer);
|
||||
|
||||
StopMoving();
|
||||
}
|
||||
|
||||
void Unit::ResumeMovement(uint32 timer /* = 0*/, uint8 slot /* = 0*/)
|
||||
{
|
||||
if (slot >= MAX_MOTION_SLOT)
|
||||
return;
|
||||
|
||||
if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(slot))
|
||||
movementGenerator->Resume(timer);
|
||||
}
|
||||
|
||||
void Unit::StopMovingOnCurrentPos() // pussywizard
|
||||
{
|
||||
ClearUnitState(UNIT_STATE_MOVING);
|
||||
|
|
@ -17649,8 +17677,16 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
|
|||
|
||||
if (GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (MovementGenerator* movementGenerator = GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE))
|
||||
{
|
||||
movementGenerator->Pause(0);
|
||||
}
|
||||
|
||||
GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE);
|
||||
|
||||
StopMoving();
|
||||
|
||||
ToCreature()->AI()->OnCharmed(true);
|
||||
GetMotionMaster()->MoveIdle();
|
||||
|
||||
// Xinef: If creature can fly, add normal player flying flag (fixes speed)
|
||||
if (charmer->GetTypeId() == TYPEID_PLAYER && ToCreature()->CanFly())
|
||||
|
|
@ -19107,7 +19143,7 @@ bool Unit::CanSwim() const
|
|||
return true;
|
||||
if (HasFlag(UNIT_FIELD_FLAGS_2, 0x1000000))
|
||||
return false;
|
||||
if (IsPet() && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT))
|
||||
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT))
|
||||
return true;
|
||||
return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_RENAME | UNIT_FLAG_SWIMMING);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2345,10 +2345,13 @@ public:
|
|||
|
||||
MotionMaster* GetMotionMaster() { return i_motionMaster; }
|
||||
[[nodiscard]] const MotionMaster* GetMotionMaster() const { return i_motionMaster; }
|
||||
[[nodiscard]] virtual MovementGeneratorType GetDefaultMovementType() const;
|
||||
|
||||
[[nodiscard]] bool IsStopped() const { return !(HasUnitState(UNIT_STATE_MOVING)); }
|
||||
void StopMoving();
|
||||
void StopMovingOnCurrentPos();
|
||||
virtual void PauseMovement(uint32 timer = 0, uint8 slot = 0); // timer in ms
|
||||
void ResumeMovement(uint32 timer = 0, uint8 slot = 0);
|
||||
|
||||
void AddUnitMovementFlag(uint32 f) { m_movementInfo.flags |= f; }
|
||||
void RemoveUnitMovementFlag(uint32 f) { m_movementInfo.flags &= ~f; }
|
||||
|
|
|
|||
|
|
@ -485,9 +485,9 @@ void ObjectMgr::LoadCreatureTemplates()
|
|||
"dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, "
|
||||
// 40 41 42 43 44 45 46 47 48 49
|
||||
"type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
|
||||
// 50 51 52 53 54 55 56 57 58 59 60 61 62
|
||||
"InhabitType, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName "
|
||||
"FROM creature_template;");
|
||||
// 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
||||
"ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName "
|
||||
"FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId;");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
|
|
@ -552,44 +552,44 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields)
|
|||
creatureTemplate.KillCredit[i] = fields[4 + i].GetUInt32();
|
||||
}
|
||||
|
||||
creatureTemplate.Modelid1 = fields[6].GetUInt32();
|
||||
creatureTemplate.Modelid2 = fields[7].GetUInt32();
|
||||
creatureTemplate.Modelid3 = fields[8].GetUInt32();
|
||||
creatureTemplate.Modelid4 = fields[9].GetUInt32();
|
||||
creatureTemplate.Name = fields[10].GetString();
|
||||
creatureTemplate.SubName = fields[11].GetString();
|
||||
creatureTemplate.IconName = fields[12].GetString();
|
||||
creatureTemplate.GossipMenuId = fields[13].GetUInt32();
|
||||
creatureTemplate.minlevel = fields[14].GetUInt8();
|
||||
creatureTemplate.maxlevel = fields[15].GetUInt8();
|
||||
creatureTemplate.expansion = uint32(fields[16].GetInt16());
|
||||
creatureTemplate.faction = uint32(fields[17].GetUInt16());
|
||||
creatureTemplate.npcflag = fields[18].GetUInt32();
|
||||
creatureTemplate.speed_walk = fields[19].GetFloat();
|
||||
creatureTemplate.speed_run = fields[20].GetFloat();
|
||||
creatureTemplate.detection_range = fields[21].GetFloat();
|
||||
creatureTemplate.scale = fields[22].GetFloat();
|
||||
creatureTemplate.rank = uint32(fields[23].GetUInt8());
|
||||
creatureTemplate.dmgschool = uint32(fields[24].GetInt8());
|
||||
creatureTemplate.DamageModifier = fields[25].GetFloat();
|
||||
creatureTemplate.BaseAttackTime = fields[26].GetUInt32();
|
||||
creatureTemplate.RangeAttackTime = fields[27].GetUInt32();
|
||||
creatureTemplate.BaseVariance = fields[28].GetFloat();
|
||||
creatureTemplate.RangeVariance = fields[29].GetFloat();
|
||||
creatureTemplate.unit_class = uint32(fields[30].GetUInt8());
|
||||
creatureTemplate.unit_flags = fields[31].GetUInt32();
|
||||
creatureTemplate.unit_flags2 = fields[32].GetUInt32();
|
||||
creatureTemplate.dynamicflags = fields[33].GetUInt32();
|
||||
creatureTemplate.family = uint32(fields[34].GetUInt8());
|
||||
creatureTemplate.trainer_type = uint32(fields[35].GetUInt8());
|
||||
creatureTemplate.trainer_spell = fields[36].GetUInt32();
|
||||
creatureTemplate.trainer_class = uint32(fields[37].GetUInt8());
|
||||
creatureTemplate.trainer_race = uint32(fields[38].GetUInt8());
|
||||
creatureTemplate.type = uint32(fields[39].GetUInt8());
|
||||
creatureTemplate.type_flags = fields[40].GetUInt32();
|
||||
creatureTemplate.lootid = fields[41].GetUInt32();
|
||||
creatureTemplate.pickpocketLootId = fields[42].GetUInt32();
|
||||
creatureTemplate.SkinLootId = fields[43].GetUInt32();
|
||||
creatureTemplate.Modelid1 = fields[6].GetUInt32();
|
||||
creatureTemplate.Modelid2 = fields[7].GetUInt32();
|
||||
creatureTemplate.Modelid3 = fields[8].GetUInt32();
|
||||
creatureTemplate.Modelid4 = fields[9].GetUInt32();
|
||||
creatureTemplate.Name = fields[10].GetString();
|
||||
creatureTemplate.SubName = fields[11].GetString();
|
||||
creatureTemplate.IconName = fields[12].GetString();
|
||||
creatureTemplate.GossipMenuId = fields[13].GetUInt32();
|
||||
creatureTemplate.minlevel = fields[14].GetUInt8();
|
||||
creatureTemplate.maxlevel = fields[15].GetUInt8();
|
||||
creatureTemplate.expansion = uint32(fields[16].GetInt16());
|
||||
creatureTemplate.faction = uint32(fields[17].GetUInt16());
|
||||
creatureTemplate.npcflag = fields[18].GetUInt32();
|
||||
creatureTemplate.speed_walk = fields[19].GetFloat();
|
||||
creatureTemplate.speed_run = fields[20].GetFloat();
|
||||
creatureTemplate.detection_range = fields[21].GetFloat();
|
||||
creatureTemplate.scale = fields[22].GetFloat();
|
||||
creatureTemplate.rank = uint32(fields[23].GetUInt8());
|
||||
creatureTemplate.dmgschool = uint32(fields[24].GetInt8());
|
||||
creatureTemplate.DamageModifier = fields[25].GetFloat();
|
||||
creatureTemplate.BaseAttackTime = fields[26].GetUInt32();
|
||||
creatureTemplate.RangeAttackTime = fields[27].GetUInt32();
|
||||
creatureTemplate.BaseVariance = fields[28].GetFloat();
|
||||
creatureTemplate.RangeVariance = fields[29].GetFloat();
|
||||
creatureTemplate.unit_class = uint32(fields[30].GetUInt8());
|
||||
creatureTemplate.unit_flags = fields[31].GetUInt32();
|
||||
creatureTemplate.unit_flags2 = fields[32].GetUInt32();
|
||||
creatureTemplate.dynamicflags = fields[33].GetUInt32();
|
||||
creatureTemplate.family = uint32(fields[34].GetUInt8());
|
||||
creatureTemplate.trainer_type = uint32(fields[35].GetUInt8());
|
||||
creatureTemplate.trainer_spell = fields[36].GetUInt32();
|
||||
creatureTemplate.trainer_class = uint32(fields[37].GetUInt8());
|
||||
creatureTemplate.trainer_race = uint32(fields[38].GetUInt8());
|
||||
creatureTemplate.type = uint32(fields[39].GetUInt8());
|
||||
creatureTemplate.type_flags = fields[40].GetUInt32();
|
||||
creatureTemplate.lootid = fields[41].GetUInt32();
|
||||
creatureTemplate.pickpocketLootId = fields[42].GetUInt32();
|
||||
creatureTemplate.SkinLootId = fields[43].GetUInt32();
|
||||
|
||||
for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
|
||||
{
|
||||
|
|
@ -601,25 +601,49 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields)
|
|||
creatureTemplate.spells[i] = 0;
|
||||
}
|
||||
|
||||
creatureTemplate.PetSpellDataId = fields[44].GetUInt32();
|
||||
creatureTemplate.VehicleId = fields[45].GetUInt32();
|
||||
creatureTemplate.mingold = fields[46].GetUInt32();
|
||||
creatureTemplate.maxgold = fields[47].GetUInt32();
|
||||
creatureTemplate.AIName = fields[48].GetString();
|
||||
creatureTemplate.MovementType = uint32(fields[49].GetUInt8());
|
||||
creatureTemplate.InhabitType = uint32(fields[50].GetUInt8());
|
||||
creatureTemplate.HoverHeight = fields[51].GetFloat();
|
||||
creatureTemplate.ModHealth = fields[52].GetFloat();
|
||||
creatureTemplate.ModMana = fields[53].GetFloat();
|
||||
creatureTemplate.ModArmor = fields[54].GetFloat();
|
||||
creatureTemplate.ModExperience = fields[55].GetFloat();
|
||||
creatureTemplate.RacialLeader = fields[56].GetBool();
|
||||
creatureTemplate.movementId = fields[57].GetUInt32();
|
||||
creatureTemplate.RegenHealth = fields[58].GetBool();
|
||||
creatureTemplate.MechanicImmuneMask = fields[59].GetUInt32();
|
||||
creatureTemplate.SpellSchoolImmuneMask = fields[60].GetUInt8();
|
||||
creatureTemplate.flags_extra = fields[61].GetUInt32();
|
||||
creatureTemplate.ScriptID = GetScriptId(fields[62].GetCString());
|
||||
creatureTemplate.PetSpellDataId = fields[44].GetUInt32();
|
||||
creatureTemplate.VehicleId = fields[45].GetUInt32();
|
||||
creatureTemplate.mingold = fields[46].GetUInt32();
|
||||
creatureTemplate.maxgold = fields[47].GetUInt32();
|
||||
creatureTemplate.AIName = fields[48].GetString();
|
||||
creatureTemplate.MovementType = uint32(fields[49].GetUInt8());
|
||||
if (!fields[50].IsNull())
|
||||
{
|
||||
creatureTemplate.Movement.Ground = static_cast<CreatureGroundMovementType>(fields[50].GetUInt8());
|
||||
}
|
||||
|
||||
creatureTemplate.Movement.Swim = fields[51].GetBool();
|
||||
if (!fields[52].IsNull())
|
||||
{
|
||||
creatureTemplate.Movement.Flight = static_cast<CreatureFlightMovementType>(fields[52].GetUInt8());
|
||||
}
|
||||
|
||||
creatureTemplate.Movement.Rooted = fields[53].GetBool();
|
||||
if (!fields[54].IsNull())
|
||||
{
|
||||
creatureTemplate.Movement.Chase = static_cast<CreatureChaseMovementType>(fields[54].GetUInt8());
|
||||
}
|
||||
if (!fields[55].IsNull())
|
||||
{
|
||||
creatureTemplate.Movement.Random = static_cast<CreatureRandomMovementType>(fields[55].GetUInt8());
|
||||
}
|
||||
if (!fields[56].IsNull())
|
||||
{
|
||||
creatureTemplate.Movement.InteractionPauseTimer = fields[56].GetUInt32();
|
||||
}
|
||||
|
||||
creatureTemplate.HoverHeight = fields[57].GetFloat();
|
||||
creatureTemplate.ModHealth = fields[58].GetFloat();
|
||||
creatureTemplate.ModMana = fields[59].GetFloat();
|
||||
creatureTemplate.ModArmor = fields[60].GetFloat();
|
||||
creatureTemplate.ModExperience = fields[61].GetFloat();
|
||||
creatureTemplate.RacialLeader = fields[62].GetBool();
|
||||
creatureTemplate.movementId = fields[63].GetUInt32();
|
||||
creatureTemplate.RegenHealth = fields[64].GetBool();
|
||||
creatureTemplate.MechanicImmuneMask = fields[65].GetUInt32();
|
||||
creatureTemplate.SpellSchoolImmuneMask = fields[66].GetUInt8();
|
||||
creatureTemplate.flags_extra = fields[67].GetUInt32();
|
||||
creatureTemplate.ScriptID = GetScriptId(fields[68].GetCString());
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadCreatureTemplateResistances()
|
||||
|
|
@ -1070,17 +1094,7 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
|
|||
const_cast<CreatureTemplate*>(cInfo)->family = 0;
|
||||
}
|
||||
|
||||
if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly.", cInfo->Entry, cInfo->InhabitType);
|
||||
const_cast<CreatureTemplate*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
|
||||
}
|
||||
|
||||
if (cInfo->InhabitType == INHABIT_ROOT)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Creature (Entry: %u) only has INHABIT_ROOT(8) as `InhabitType`, creature will not behave correctly.", cInfo->Entry);
|
||||
const_cast<CreatureTemplate*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
|
||||
}
|
||||
CheckCreatureMovement("creature_template_movement", cInfo->Entry, const_cast<CreatureTemplate*>(cInfo)->Movement);
|
||||
|
||||
if (cInfo->HoverHeight < 0.0f)
|
||||
{
|
||||
|
|
@ -1144,6 +1158,33 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
|
|||
const_cast<CreatureTemplate*>(cInfo)->DamageModifier *= Creature::_GetDamageMod(cInfo->rank);
|
||||
}
|
||||
|
||||
void ObjectMgr::CheckCreatureMovement(char const* table, uint64 id, CreatureMovementData& creatureMovement)
|
||||
{
|
||||
if (creatureMovement.Ground >= CreatureGroundMovementType::Max)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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.Chase >= CreatureChaseMovementType::Max)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`%s`.`Chase` wrong value (%u) for Id " UI64FMTD ", setting to Run.", table, uint32(creatureMovement.Chase), id);
|
||||
creatureMovement.Chase = CreatureChaseMovementType::Run;
|
||||
}
|
||||
|
||||
if (creatureMovement.Random >= CreatureRandomMovementType::Max)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "`%s`.`Random` wrong value (%u) for Id " UI64FMTD ", setting to Walk.", table, uint32(creatureMovement.Random), id);
|
||||
creatureMovement.Random = CreatureRandomMovementType::Walk;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadCreatureAddons()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
|
@ -1315,6 +1356,11 @@ CreatureAddon const* ObjectMgr::GetCreatureTemplateAddon(uint32 entry)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CreatureMovementData const* ObjectMgr::GetCreatureMovementOverride(ObjectGuid::LowType spawnId) const
|
||||
{
|
||||
return Acore::Containers::MapGetValuePtr(_creatureMovementOverrides, spawnId);
|
||||
}
|
||||
|
||||
EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry, int8& id)
|
||||
{
|
||||
EquipmentInfoContainer::const_iterator itr = _equipmentInfoStore.find(entry);
|
||||
|
|
@ -1419,6 +1465,82 @@ void ObjectMgr::LoadEquipmentTemplates()
|
|||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadCreatureMovementOverrides()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
_creatureMovementOverrides.clear();
|
||||
|
||||
// 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.Chase, ctm.Chase),"
|
||||
"COALESCE(cmo.Random, ctm.Random),"
|
||||
"COALESCE(cmo.InteractionPauseTimer, ctm.InteractionPauseTimer) "
|
||||
"FROM creature_movement_override AS cmo "
|
||||
"LEFT JOIN creature AS c ON c.guid = cmo.SpawnId "
|
||||
"LEFT JOIN creature_template_movement AS ctm ON ctm.CreatureId = c.id");
|
||||
if (!result)
|
||||
{
|
||||
LOG_INFO("server.loading", ">> Loaded 0 creature movement overrides. DB table `creature_movement_override` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
ObjectGuid::LowType spawnId = fields[0].GetUInt32();
|
||||
if (!GetCreatureData(spawnId))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Creature (GUID: %u) does not exist but has a record in `creature_movement_override`", spawnId);
|
||||
continue;
|
||||
}
|
||||
|
||||
CreatureMovementData& movement = _creatureMovementOverrides[spawnId];
|
||||
if (!fields[1].IsNull())
|
||||
{
|
||||
movement.Ground = static_cast<CreatureGroundMovementType>(fields[1].GetUInt8());
|
||||
}
|
||||
|
||||
if (!fields[2].IsNull())
|
||||
{
|
||||
movement.Swim = fields[2].GetBool();
|
||||
}
|
||||
|
||||
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.Chase = static_cast<CreatureChaseMovementType>(fields[5].GetUInt8());
|
||||
}
|
||||
|
||||
if (!fields[6].IsNull())
|
||||
{
|
||||
movement.Random = static_cast<CreatureRandomMovementType>(fields[6].GetUInt8());
|
||||
}
|
||||
|
||||
if (!fields[7].IsNull())
|
||||
{
|
||||
movement.InteractionPauseTimer = fields[7].GetUInt32();
|
||||
}
|
||||
|
||||
CheckCreatureMovement("creature_movement_override", spawnId, movement);
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded " SZFMTD " movement overrides in %u ms", _creatureMovementOverrides.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelId)
|
||||
{
|
||||
CreatureModelContainer::const_iterator itr = _creatureModelStore.find(modelId);
|
||||
|
|
|
|||
|
|
@ -749,6 +749,7 @@ public:
|
|||
GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid);
|
||||
[[nodiscard]] GameObjectTemplateAddon const* GetGameObjectTemplateAddon(uint32 entry) const;
|
||||
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
|
||||
CreatureMovementData const* GetCreatureMovementOverride(ObjectGuid::LowType spawnId) const;
|
||||
ItemTemplate const* GetItemTemplate(uint32 entry);
|
||||
[[nodiscard]] ItemTemplateContainer const* GetItemTemplateStore() const { return &_itemTemplateStore; }
|
||||
[[nodiscard]] std::vector<ItemTemplate*> const* GetItemTemplateStoreFast() const { return &_itemTemplateStoreFast; }
|
||||
|
|
@ -989,6 +990,7 @@ public:
|
|||
void LoadCreatureTemplateResistances();
|
||||
void LoadCreatureTemplateSpells();
|
||||
void CheckCreatureTemplate(CreatureTemplate const* cInfo);
|
||||
void CheckCreatureMovement(char const* table, uint64 id, CreatureMovementData& creatureMovement);
|
||||
void LoadGameObjectQuestItems();
|
||||
void LoadCreatureQuestItems();
|
||||
void LoadTempSummons();
|
||||
|
|
@ -999,6 +1001,7 @@ public:
|
|||
void LoadGameObjectAddons();
|
||||
void LoadCreatureModelInfo();
|
||||
void LoadEquipmentTemplates();
|
||||
void LoadCreatureMovementOverrides();
|
||||
void LoadGameObjectLocales();
|
||||
void LoadGameobjects();
|
||||
void LoadItemTemplates();
|
||||
|
|
@ -1491,6 +1494,7 @@ private:
|
|||
CreatureModelContainer _creatureModelStore;
|
||||
CreatureAddonContainer _creatureAddonStore;
|
||||
CreatureAddonContainer _creatureTemplateAddonStore;
|
||||
std::unordered_map<ObjectGuid::LowType, CreatureMovementData> _creatureMovementOverrides;
|
||||
GameObjectAddonContainer _gameObjectAddonStore;
|
||||
GameObjectQuestItemMap _gameObjectQuestItemStore;
|
||||
CreatureQuestItemMap _creatureQuestItemStore;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ void WorldSession::HandleBattlemasterHelloOpcode(WorldPacket& recvData)
|
|||
return;
|
||||
|
||||
// Stop the npc if moving
|
||||
unit->StopMoving();
|
||||
if (uint32 pause = unit->GetMovementTemplate().GetInteractionPauseTimer())
|
||||
unit->PauseMovement(pause);
|
||||
unit->SetHomePosition(unit->GetPosition());
|
||||
|
||||
BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(unit->GetEntry());
|
||||
|
||||
|
|
|
|||
|
|
@ -1001,10 +1001,9 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid, uint32 vendorEntry)
|
|||
}
|
||||
|
||||
// Stop the npc if moving
|
||||
if (vendor->HasUnitState(UNIT_STATE_MOVING))
|
||||
{
|
||||
vendor->StopMoving();
|
||||
}
|
||||
if (uint32 pause = vendor->GetMovementTemplate().GetInteractionPauseTimer())
|
||||
vendor->PauseMovement(pause);
|
||||
vendor->SetHomePosition(vendor->GetPosition());
|
||||
|
||||
SetCurrentVendor(vendorEntry);
|
||||
|
||||
|
|
|
|||
|
|
@ -491,6 +491,13 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
|
|||
}
|
||||
}
|
||||
|
||||
if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater())
|
||||
{
|
||||
// now client not include swimming flag in case jumping under water
|
||||
plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetMap()->IsUnderWater(plrMover->GetPhaseMask(), movementInfo.pos.GetPositionX(),
|
||||
movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ(), plrMover->GetCollisionHeight()));
|
||||
}
|
||||
|
||||
bool jumpopcode = false;
|
||||
if (opcode == MSG_MOVE_JUMP)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -302,12 +302,10 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData)
|
|||
//if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
// GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// xinef: and if he has pure gossip or is banker and moves or is tabard designer?
|
||||
//if (unit->IsArmorer() || unit->IsCivilian() || unit->IsQuestGiver() || unit->IsServiceProvider() || unit->IsGuard())
|
||||
{
|
||||
//if (!unit->GetTransport()) // pussywizard: reverted with new spline (old: without this check, npc would stay in place and the transport would continue moving, so the npc falls off. NPCs on transports don't have waypoints, so stopmoving is not needed)
|
||||
unit->StopMoving();
|
||||
}
|
||||
// Stop the npc if moving
|
||||
if (uint32 pause = unit->GetMovementTemplate().GetInteractionPauseTimer())
|
||||
unit->PauseMovement(pause);
|
||||
unit->SetHomePosition(unit->GetPosition());
|
||||
|
||||
// If spiritguide, no need for gossip menu, just put player into resurrect queue
|
||||
if (unit->IsSpiritGuide())
|
||||
|
|
|
|||
|
|
@ -90,9 +90,11 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket& recvData)
|
|||
// remove fake death
|
||||
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
|
||||
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
|
||||
|
||||
// Stop the npc if moving
|
||||
//if (!creature->GetTransport()) // pussywizard: reverted with new spline (old: without this check, npc would stay in place and the transport would continue moving, so the npc falls off. NPCs on transports don't have waypoints, so stopmoving is not needed)
|
||||
creature->StopMoving();
|
||||
if (uint32 pause = creature->GetMovementTemplate().GetInteractionPauseTimer())
|
||||
creature->PauseMovement(pause);
|
||||
creature->SetHomePosition(creature->GetPosition());
|
||||
|
||||
if (sScriptMgr->OnGossipHello(_player, creature))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1395,7 +1395,7 @@ enum AcoreStrings
|
|||
LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006,
|
||||
LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007,
|
||||
|
||||
LANG_NPCINFO_INHABIT_TYPE = 11008,
|
||||
LANG_NPCINFO_MOVEMENT_DATA = 11008,
|
||||
LANG_NPCINFO_FLAGS_EXTRA = 11009,
|
||||
LANG_INSTANCE_LOGIN_GAMEMASTER_EXCEPTION = 11010,
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ public:
|
|||
|
||||
virtual void unitSpeedChanged() { }
|
||||
|
||||
// timer in ms
|
||||
virtual void Pause(uint32 /* timer = 0*/) {}
|
||||
// timer in ms
|
||||
virtual void Resume(uint32 /* overrideTimer = 0*/) {}
|
||||
|
||||
// used by Evade code for select point to evade with expected restart default movement
|
||||
virtual bool GetResetPosition(float& /*x*/, float& /*y*/, float& /*z*/) { return false; }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -195,18 +195,30 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
|
|||
_currDestPosition.Relocate(finalPoint.x, finalPoint.y, finalPoint.z);
|
||||
|
||||
creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||
++_moveCount;
|
||||
if (roll_chance_i((int32)_moveCount * 25 + 10))
|
||||
bool walk = true;
|
||||
switch (creature->GetMovementTemplate().GetRandom())
|
||||
{
|
||||
_moveCount = 0;
|
||||
_nextMoveTime.Reset(urand(4000, 8000));
|
||||
case CreatureRandomMovementType::CanRun:
|
||||
walk = creature->IsWalking();
|
||||
break;
|
||||
case CreatureRandomMovementType::AlwaysRun:
|
||||
walk = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Movement::MoveSplineInit init(creature);
|
||||
init.MovebyPath(finalPath);
|
||||
init.SetWalk(true);
|
||||
init.SetWalk(walk);
|
||||
init.Launch();
|
||||
|
||||
++_moveCount;
|
||||
if (roll_chance_i((int32) _moveCount * 25 + 10))
|
||||
{
|
||||
_moveCount = 0;
|
||||
_nextMoveTime.Reset(urand(4000, 8000));
|
||||
}
|
||||
if (sWorld->getBoolConfig(CONFIG_DONT_CACHE_RANDOM_MOVEMENT_PATHS))
|
||||
_preComputedPaths.erase(pathIdx);
|
||||
|
||||
|
|
|
|||
|
|
@ -189,7 +189,18 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
|||
bool walk = false;
|
||||
if (cOwner && !cOwner->IsPet())
|
||||
{
|
||||
walk = owner->IsWalking();
|
||||
switch (cOwner->GetMovementTemplate().GetChase())
|
||||
{
|
||||
case CreatureChaseMovementType::CanWalk:
|
||||
if (owner->IsWalking())
|
||||
walk = true;
|
||||
break;
|
||||
case CreatureChaseMovementType::AlwaysWalk:
|
||||
walk = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
|
||||
|
|
|
|||
|
|
@ -217,6 +217,7 @@ enum WorldIntConfigs
|
|||
CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK,
|
||||
CONFIG_CHARACTERS_PER_ACCOUNT,
|
||||
CONFIG_CHARACTERS_PER_REALM,
|
||||
CONFIG_CREATURE_STOP_FOR_PLAYER,
|
||||
CONFIG_HEROIC_CHARACTERS_PER_REALM,
|
||||
CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER,
|
||||
CONFIG_SKIP_CINEMATICS,
|
||||
|
|
|
|||
|
|
@ -1167,6 +1167,7 @@ void World::LoadConfigSettings(bool reload)
|
|||
m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetOption<bool> ("Arena.QueueAnnouncer.PlayerOnly", false);
|
||||
|
||||
m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetOption<bool>("OffhandCheckAtSpellUnlearn", true);
|
||||
m_int_configs[CONFIG_CREATURE_STOP_FOR_PLAYER] = sConfigMgr->GetOption<int32>("Creature.MovingStopTimeForPlayer", 3 * MINUTE * IN_MILLISECONDS);
|
||||
|
||||
if (int32 clientCacheId = sConfigMgr->GetOption<int32>("ClientCacheVersion", 0))
|
||||
{
|
||||
|
|
@ -1688,6 +1689,9 @@ void World::SetInitialWorldSettings()
|
|||
LOG_INFO("server.loading", "Loading Creature Addon Data...");
|
||||
sObjectMgr->LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures()
|
||||
|
||||
LOG_INFO("server.loading", "Loading Creature Movement Overrides...");
|
||||
sObjectMgr->LoadCreatureMovementOverrides(); // must be after LoadCreatures()
|
||||
|
||||
LOG_INFO("server.loading", "Loading Gameobject Data...");
|
||||
sObjectMgr->LoadGameobjects();
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ public:
|
|||
{ "creature_questender", HandleReloadCreatureQuestEnderCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "creature_linked_respawn", HandleReloadLinkedRespawnCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "creature_loot_template", HandleReloadLootTemplatesCreatureCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "creature_onkill_reputation", HandleReloadOnKillReputationCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "creature_movement_override", HandleReloadCreatureMovementOverrideCommand, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{ "creature_onkill_reputation", HandleReloadOnKillReputationCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "creature_queststarter", HandleReloadCreatureQuestStarterCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "creature_template", HandleReloadCreatureTemplateCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "disables", HandleReloadDisablesCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
|
|
@ -198,6 +199,7 @@ public:
|
|||
HandleReloadReservedNameCommand(handler);
|
||||
HandleReloadAcoreStringCommand(handler);
|
||||
HandleReloadGameTeleCommand(handler);
|
||||
HandleReloadCreatureMovementOverrideCommand(handler);
|
||||
|
||||
HandleReloadVehicleAccessoryCommand(handler);
|
||||
HandleReloadVehicleTemplateAccessoryCommand(handler);
|
||||
|
|
@ -550,6 +552,14 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadCreatureMovementOverrideCommand(ChatHandler* handler)
|
||||
{
|
||||
LOG_INFO("server.loading", "Re-Loading Creature movement overrides...");
|
||||
sObjectMgr->LoadCreatureMovementOverrides();
|
||||
handler->SendGlobalGMSysMessage("DB table `creature_movement_override` reloaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadLootTemplatesDisenchantCommand(ChatHandler* handler)
|
||||
{
|
||||
LOG_INFO("server.loading", "Re-Loading Loot Tables... (`disenchant_loot_template`)");
|
||||
|
|
|
|||
|
|
@ -1758,6 +1758,14 @@ ListenRange.TextEmote = 40
|
|||
|
||||
ListenRange.Yell = 300
|
||||
|
||||
#
|
||||
# Creature.MovingStopTimeForPlayer
|
||||
# Description: Time (in milliseconds) during which creature will not move after
|
||||
# interaction with player.
|
||||
# Default: 180000
|
||||
|
||||
Creature.MovingStopTimeForPlayer = 180000
|
||||
|
||||
# WaypointMovementStopTimeForPlayer
|
||||
# Description: Specifies the time (in seconds) that a creature with waypoint
|
||||
# movement will wait after a player interacts with it.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue