Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-06-01 14:55:09 +08:00
66 changed files with 1638 additions and 550 deletions

View File

@@ -2672,29 +2672,30 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool skipDistCheck) const
// pussywizard: don't check distance to home position if recently damaged (allow kiting away from spawnpoint!)
// xinef: this should include taunt auras
if (!isWorldBoss() && (GetLastLeashExtensionTime() + 12 > GameTime::GetGameTime().count() || HasTauntAura()))
if (!isWorldBoss() && (GetLastLeashExtensionTime() + GetLeashTimer() > GameTime::GetGameTime().count() || HasTauntAura()))
return true;
}
if (skipDistCheck)
return true;
// xinef: added size factor for huge npcs
float dist = std::min<float>(GetDetectionRange() + GetObjectSize() * 2, 150.0f);
float dist = sWorld->getFloatConfig(CONFIG_CREATURE_LEASH_RADIUS);
if (Unit* unit = GetCharmerOrOwner())
if (GetCharmerOrOwner())
{
dist = std::min<float>(GetMap()->GetVisibilityRange() + GetObjectSize() * 2, 150.0f);
return victim->IsWithinDist(unit, dist);
return IsWithinDist(victim, dist);
}
if (!dist)
return true;
float x, y, z;
x = y = z = 0.0f;
if (GetMotionMaster()->GetMotionSlot(MOTION_SLOT_IDLE)->GetResetPosition(x, y, z))
return IsInDist2d(x, y, dist);
else
{
// to prevent creatures in air ignore attacks because distance is already too high...
if (GetMovementTemplate().IsFlightAllowed())
return victim->IsInDist2d(&m_homePosition, dist);
else
return victim->IsInDist(&m_homePosition, dist);
}
return IsInDist2d(&m_homePosition, dist);
}
CreatureAddon const* Creature::GetCreatureAddon() const
@@ -3730,6 +3731,16 @@ void Creature::UpdateLeashExtensionTime()
(*GetLastLeashExtensionTimePtr()) = GameTime::GetGameTime().count();
}
uint8 Creature::GetLeashTimer() const
{ // Based on testing on Classic, seems to range from ~11s for low level mobs (1-5) to ~16s for high level mobs (70+)
uint8 timerOffset = 11;
uint8 timerModifier = uint8(GetLevel() / 10) - 2;
// Formula is likely not quite correct, but better than flat timer
return std::max<uint8>(timerOffset, timerOffset + timerModifier);
}
bool Creature::CanPeriodicallyCallForAssistance() const
{
if (!IsInCombat())

View File

@@ -391,6 +391,7 @@ public:
void ClearLastLeashExtensionTimePtr();
time_t GetLastLeashExtensionTime() const;
void UpdateLeashExtensionTime();
uint8 GetLeashTimer() const;
bool IsFreeToMove();
static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000;

View File

@@ -8840,13 +8840,7 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId)
battlefield->FillInitialWorldStates(packet);
break;
}
[[fallthrough]];
default:
packet.Worldstates.reserve(4);
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_2, 0);
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_1, 0);
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_0, 0);
packet.Worldstates.emplace_back(WORLD_STATE_GENERIC_UNK_3, 0);
break;
}
}

View File

@@ -51,17 +51,17 @@ void Totem::InitStats(uint32 duration)
if (Unit* owner = ObjectAccessor::GetUnit(*this, m_owner))
{
uint32 slot = m_Properties->Slot;
if (owner->IsPlayer() && slot >= SUMMON_SLOT_TOTEM && slot < MAX_TOTEM_SLOT)
if (owner->IsPlayer() && slot >= SUMMON_SLOT_TOTEM_FIRE && slot < MAX_TOTEM_SLOT)
{
WorldPackets::Totem::TotemCreated data;
data.Totem = GetGUID();
data.Slot = slot - SUMMON_SLOT_TOTEM;
data.Slot = slot - SUMMON_SLOT_TOTEM_FIRE;
data.Duration = duration;
data.SpellID = GetUInt32Value(UNIT_CREATED_BY_SPELL);
owner->ToPlayer()->SendDirectMessage(data.Write());
// set display id depending on caster's race
SetDisplayId(owner->GetModelForTotem(PlayerTotemType(m_Properties->Id)));
SetDisplayId(sObjectMgr->GetModelForTotem(SummonSlot(slot), Races(owner->getRace())));
}
SetLevel(owner->GetLevel());
@@ -133,7 +133,7 @@ void Totem::UnSummon(uint32 msTime)
if (Unit* owner = GetOwner())
{
// clear owner's totem slot
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
for (uint8 i = SUMMON_SLOT_TOTEM_FIRE; i < MAX_TOTEM_SLOT; ++i)
{
if (owner->m_SummonSlot[i] == GetGUID())
{

View File

@@ -19261,7 +19261,7 @@ uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float c
return CalculatePct(damage, percent);
}
uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId) const
uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId)
{
// Hardcoded cases
switch (spellId)
@@ -19276,177 +19276,8 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId) const
if (IsPlayer())
{
switch (form)
{
case FORM_CAT:
// Based on Hair color
if (getRace() == RACE_NIGHTELF)
{
uint8 hairColor = GetByteValue(PLAYER_BYTES, 3);
switch (hairColor)
{
case 7: // Violet
case 8:
return 29405;
case 3: // Light Blue
return 29406;
case 0: // Green
case 1: // Light Green
case 2: // Dark Green
return 29407;
case 4: // White
return 29408;
default: // original - Dark Blue
return 892;
}
}
// Based on Skin color
else if (getRace() == RACE_TAUREN)
{
uint8 skinColor = GetByteValue(PLAYER_BYTES, 0);
// Male
if (getGender() == GENDER_MALE)
{
switch (skinColor)
{
case 12: // White
case 13:
case 14:
case 18: // Completly White
return 29409;
case 9: // Light Brown
case 10:
case 11:
return 29410;
case 6: // Brown
case 7:
case 8:
return 29411;
case 0: // Dark
case 1:
case 2:
case 3: // Dark Grey
case 4:
case 5:
return 29412;
default: // original - Grey
return 8571;
}
}
// Female
else switch (skinColor)
{
case 10: // White
return 29409;
case 6: // Light Brown
case 7:
return 29410;
case 4: // Brown
case 5:
return 29411;
case 0: // Dark
case 1:
case 2:
case 3:
return 29412;
default: // original - Grey
return 8571;
}
}
else if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
return 892;
else
return 8571;
case FORM_DIREBEAR:
case FORM_BEAR:
// Based on Hair color
if (getRace() == RACE_NIGHTELF)
{
uint8 hairColor = GetByteValue(PLAYER_BYTES, 3);
switch (hairColor)
{
case 0: // Green
case 1: // Light Green
case 2: // Dark Green
return 29413; // 29415?
case 6: // Dark Blue
return 29414;
case 4: // White
return 29416;
case 3: // Light Blue
return 29417;
default: // original - Violet
return 2281;
}
}
// Based on Skin color
else if (getRace() == RACE_TAUREN)
{
uint8 skinColor = GetByteValue(PLAYER_BYTES, 0);
// Male
if (getGender() == GENDER_MALE)
{
switch (skinColor)
{
case 0: // Dark (Black)
case 1:
case 2:
return 29418;
case 3: // White
case 4:
case 5:
case 12:
case 13:
case 14:
return 29419;
case 9: // Light Brown/Grey
case 10:
case 11:
case 15:
case 16:
case 17:
return 29420;
case 18: // Completly White
return 29421;
default: // original - Brown
return 2289;
}
}
// Female
else switch (skinColor)
{
case 0: // Dark (Black)
case 1:
return 29418;
case 2: // White
case 3:
return 29419;
case 6: // Light Brown/Grey
case 7:
case 8:
case 9:
return 29420;
case 10: // Completly White
return 29421;
default: // original - Brown
return 2289;
}
}
else if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
return 2281;
else
return 2289;
case FORM_FLIGHT:
if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
return 20857;
return 20872;
case FORM_FLIGHT_EPIC:
if (Player::TeamIdForRace(getRace()) == TEAM_ALLIANCE)
return 21243;
return 21244;
default:
break;
}
if (uint32 ModelId = sObjectMgr->GetModelForShapeshift(form, ToPlayer()))
return ModelId;
}
uint32 modelid = 0;
@@ -19472,104 +19303,6 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form, uint32 spellId) const
return modelid;
}
uint32 Unit::GetModelForTotem(PlayerTotemType totemType)
{
switch (getRace())
{
case RACE_ORC:
{
switch (totemType)
{
case SUMMON_TYPE_TOTEM_FIRE: // fire
return 30758;
case SUMMON_TYPE_TOTEM_EARTH: // earth
return 30757;
case SUMMON_TYPE_TOTEM_WATER: // water
return 30759;
case SUMMON_TYPE_TOTEM_AIR: // air
return 30756;
}
break;
}
case RACE_DWARF:
{
switch (totemType)
{
case SUMMON_TYPE_TOTEM_FIRE: // fire
return 30754;
case SUMMON_TYPE_TOTEM_EARTH: // earth
return 30753;
case SUMMON_TYPE_TOTEM_WATER: // water
return 30755;
case SUMMON_TYPE_TOTEM_AIR: // air
return 30736;
}
break;
}
case RACE_TROLL:
{
switch (totemType)
{
case SUMMON_TYPE_TOTEM_FIRE: // fire
return 30762;
case SUMMON_TYPE_TOTEM_EARTH: // earth
return 30761;
case SUMMON_TYPE_TOTEM_WATER: // water
return 30763;
case SUMMON_TYPE_TOTEM_AIR: // air
return 30760;
}
break;
}
case RACE_TAUREN:
{
switch (totemType)
{
case SUMMON_TYPE_TOTEM_FIRE: // fire
return 4589;
case SUMMON_TYPE_TOTEM_EARTH: // earth
return 4588;
case SUMMON_TYPE_TOTEM_WATER: // water
return 4587;
case SUMMON_TYPE_TOTEM_AIR: // air
return 4590;
}
break;
}
case RACE_DRAENEI:
{
switch (totemType)
{
case SUMMON_TYPE_TOTEM_FIRE: // fire
return 19074;
case SUMMON_TYPE_TOTEM_EARTH: // earth
return 19073;
case SUMMON_TYPE_TOTEM_WATER: // water
return 19075;
case SUMMON_TYPE_TOTEM_AIR: // air
return 19071;
}
break;
}
default: // One standard for other races.
{
switch (totemType)
{
case SUMMON_TYPE_TOTEM_FIRE: // fire
return 4589;
case SUMMON_TYPE_TOTEM_EARTH: // earth
return 4588;
case SUMMON_TYPE_TOTEM_WATER: // water
return 4587;
case SUMMON_TYPE_TOTEM_AIR: // air
return 4590;
}
break;
}
}
return 0;
}
Unit* Unit::GetRedirectThreatTarget() const
{
return _redirectThreatInfo.GetTargetGUID() ? ObjectAccessor::GetUnit(*this, _redirectThreatInfo.GetTargetGUID()) : nullptr;

View File

@@ -26,6 +26,7 @@
#include "ItemTemplate.h"
#include "MotionMaster.h"
#include "Object.h"
#include "SharedDefines.h"
#include "SpellAuraDefines.h"
#include "SpellDefines.h"
#include "ThreatMgr.h"
@@ -599,23 +600,6 @@ enum ReactiveType
MAX_REACTIVE
};
#define SUMMON_SLOT_PET 0
#define SUMMON_SLOT_TOTEM 1
#define MAX_TOTEM_SLOT 5
#define SUMMON_SLOT_MINIPET 5
#define SUMMON_SLOT_QUEST 6
#define MAX_SUMMON_SLOT 7
#define MAX_GAMEOBJECT_SLOT 4
enum PlayerTotemType
{
SUMMON_TYPE_TOTEM_FIRE = 63,
SUMMON_TYPE_TOTEM_EARTH = 81,
SUMMON_TYPE_TOTEM_WATER = 82,
SUMMON_TYPE_TOTEM_AIR = 83,
};
/// Spell cooldown flags sent in SMSG_SPELL_COOLDOWN
enum SpellCooldownFlags
{
@@ -1898,8 +1882,7 @@ public:
void RestoreDisplayId();
void SetNativeDisplayId(uint32 displayId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, displayId); }
[[nodiscard]] uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const;
uint32 GetModelForTotem(PlayerTotemType totemType);
[[nodiscard]] uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId);
// Unit positons
[[nodiscard]] virtual bool IsInWater() const;