Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
bash
2025-09-20 22:17:46 +02:00
committed by GitHub
30 changed files with 840 additions and 178 deletions
@@ -3002,6 +3002,15 @@ ListenRange.TextEmote = 40
ListenRange.Yell = 300
#
# Creature.RepositionAgainstNpcs
# Description: Enables circling and backwards repositioning during NPC versus NPC combat.
# Set to 0 to keep the legacy optimization that disables these moves for NPCs.
# Default: 1 - (Enabled, uses more CPU, but looks better)
# 0 - (Disabled, uses less CPU)
Creature.RepositionAgainstNpcs = 1
#
# Creature.MovingStopTimeForPlayer
# Description: Time (in milliseconds) during which creature will not move after
+15 -4
View File
@@ -27,6 +27,7 @@
#include "Player.h"
#include "ScriptMgr.h"
#include "TemporarySummon.h"
#include "World.h"
#include "Vehicle.h"
#include "ZoneScript.h"
#include <functional>
@@ -364,13 +365,18 @@ void CreatureAI::MoveCircleChecks()
if (
!victim ||
!me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
!me->IsWithinMeleeRange(victim) || me == victim->GetVictim() ||
(!victim->IsPlayer() && !victim->IsPet()) // only player & pets to save CPU
!me->IsWithinMeleeRange(victim) || me == victim->GetVictim()
)
{
return;
}
/**
* optimization, disable circling movement for NPC vs NPC combat
*/
if (!sWorld->getBoolConfig(CONFIG_CREATURE_REPOSITION_AGAINST_NPCS) && !victim->IsPlayer() && !victim->IsPet())
return;
me->GetMotionMaster()->MoveCircleTarget(me->GetVictim());
}
@@ -378,8 +384,13 @@ void CreatureAI::MoveBackwardsChecks()
{
Unit *victim = me->GetVictim();
if (!victim || !me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
(!victim->IsPlayer() && !victim->IsPet()))
if (!victim || !me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT))
return;
/**
* optimization, disable backwards movement for NPC vs NPC combat
*/
if (!sWorld->getBoolConfig(CONFIG_CREATURE_REPOSITION_AGAINST_NPCS) && !victim->IsPlayer() && !victim->IsPet())
{
return;
}
+4
View File
@@ -29,6 +29,7 @@ class Unit;
class Creature;
class Player;
class SpellInfo;
enum SpellFinishReason : uint8;
typedef std::vector<AreaBoundary const*> CreatureBoundary;
@@ -146,6 +147,9 @@ public:
// Called when spell hits a target
virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) {}
// Called when a spell either finishes, interrupts or cancels a spell cast
virtual void OnSpellCastFinished(SpellInfo const* /*spell*/, SpellFinishReason /*reason*/) {}
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
virtual void AttackedBy(Unit* /*attacker*/) {}
virtual bool IsEscorted() { return false; }
@@ -1846,6 +1846,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
WorldObject* target = nullptr;
SAIBool isForced = !e.action.moveToPos.disableForceDestination;
switch (e.GetTargetType())
{
case SMART_TARGET_POSITION:
@@ -1855,7 +1857,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (TransportBase* trans = me->GetDirectTransport())
trans->CalculatePassengerPosition(dest.x, dest.y, dest.z);
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, dest.x, dest.y, dest.z, true, true,
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, dest.x, dest.y, dest.z, true, isForced,
isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE, e.target.o);
break;
@@ -1873,7 +1875,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
randomPoint.m_positionY,
randomPoint.m_positionZ,
true,
true,
isForced,
isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE
);
@@ -1898,7 +1900,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
else if (e.action.moveToPos.ContactDistance)
target->GetNearPoint(me, x, y, z, e.action.moveToPos.ContactDistance, 0, target->GetAngle(me));
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, x + e.target.x, y + e.target.y, z + e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, x + e.target.x, y + e.target.y, z + e.target.z, true, isForced, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
break;
}
@@ -1912,8 +1914,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
if (IsCreature(target))
{
SAIBool isForced = !e.action.moveToPosTarget.disableForceDestination;
Creature* ctarget = target->ToCreature();
ctarget->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, e.target.x, e.target.y, e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
ctarget->GetMotionMaster()->MovePoint(e.action.moveToPosTarget.pointId, e.target.x, e.target.y, e.target.z, true, isForced, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
}
}
@@ -855,7 +855,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_SET_HOVER: return sizeof(SmartAction::setHover);
case SMART_ACTION_SET_HEALTH_PCT: return sizeof(SmartAction::setHealthPct);
// case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::raw);
case SMART_ACTION_MOVE_TO_POS_TARGET: return sizeof(SmartAction::moveToPos);
case SMART_ACTION_MOVE_TO_POS_TARGET: return sizeof(SmartAction::moveToPosTarget);
case SMART_ACTION_EXIT_VEHICLE: return NO_PARAMS;
case SMART_ACTION_SET_UNIT_MOVEMENT_FLAGS: return sizeof(SmartAction::movementFlag);
case SMART_ACTION_SET_COMBAT_DISTANCE: return sizeof(SmartAction::combatDistance);
@@ -1216,8 +1216,15 @@ struct SmartAction
uint32 controlled;
uint32 ContactDistance;
uint32 combatReach;
SAIBool disableForceDestination;
} moveToPos;
struct
{
uint32 pointId;
SAIBool disableForceDestination;
} moveToPosTarget;
struct
{
uint32 gossipMenuId;
@@ -692,7 +692,6 @@ struct ItemTemplate
uint32 MinMoneyLoot;
uint32 MaxMoneyLoot;
ItemFlagsCustom FlagsCu;
WorldPacket queryData; // pussywizard
// helpers
[[nodiscard]] bool HasSignature() const
@@ -828,8 +827,6 @@ struct ItemTemplate
[[nodiscard]] bool HasFlag(ItemFlags flag) const { return (Flags & flag) != 0; }
[[nodiscard]] bool HasFlag2(ItemFlags2 flag) const { return (Flags2 & flag) != 0; }
[[nodiscard]] bool HasFlagCu(ItemFlagsCustom flag) const { return (FlagsCu & flag) != 0; }
void InitializeQueryData();
};
// Benchmarked: Faster than std::map (insert/find)
+3
View File
@@ -4138,6 +4138,9 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi
if (ai->CanChaseOnInterrupt())
ai->SetCombatMove(true);
}
if (IsCreature() && IsAIEnabled)
ToCreature()->AI()->OnSpellCastFinished(spell->GetSpellInfo(), SPELL_FINISHED_CANCELED);
}
}
-3
View File
@@ -3443,9 +3443,6 @@ void ObjectMgr::LoadItemTemplates()
}
}
for (ItemTemplateContainer::iterator itr = _itemTemplateStore.begin(); itr != _itemTemplateStore.end(); ++itr)
itr->second.InitializeQueryData();
// Check if item templates for DBC referenced character start outfit are present
std::set<uint32> notFoundOutfit;
for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i)
-129
View File
@@ -385,135 +385,6 @@ bool ItemTemplate::HasSpellPowerStat() const
return invalid;
}
void ItemTemplate::InitializeQueryData()
{
queryData.Initialize(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 1);
queryData << ItemId;
queryData << Class;
queryData << SubClass;
queryData << SoundOverrideSubclass;
queryData << Name1;
queryData << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
queryData << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00);
queryData << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00);
queryData << DisplayInfoID;
queryData << Quality;
queryData << Flags;
queryData << Flags2;
queryData << BuyPrice;
queryData << SellPrice;
queryData << InventoryType;
queryData << AllowableClass;
queryData << AllowableRace;
queryData << ItemLevel;
queryData << RequiredLevel;
queryData << RequiredSkill;
queryData << RequiredSkillRank;
queryData << RequiredSpell;
queryData << RequiredHonorRank;
queryData << RequiredCityRank;
queryData << RequiredReputationFaction;
queryData << RequiredReputationRank;
queryData << int32(MaxCount);
queryData << int32(Stackable);
queryData << ContainerSlots;
queryData << StatsCount; // item stats count
for (uint32 i = 0; i < StatsCount; ++i)
{
queryData << ItemStat[i].ItemStatType;
queryData << ItemStat[i].ItemStatValue;
}
queryData << ScalingStatDistribution; // scaling stats distribution
queryData << ScalingStatValue; // some kind of flags used to determine stat values column
for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
queryData << Damage[i].DamageMin;
queryData << Damage[i].DamageMax;
queryData << Damage[i].DamageType;
}
// resistances (7)
queryData << Armor;
queryData << HolyRes;
queryData << FireRes;
queryData << NatureRes;
queryData << FrostRes;
queryData << ShadowRes;
queryData << ArcaneRes;
queryData << Delay;
queryData << AmmoType;
queryData << RangedModRange;
for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
// use `item_template` or if not set then only use spell cooldowns
SpellInfo const* spell = sSpellMgr->GetSpellInfo(Spells[s].SpellId);
if (spell)
{
bool db_data = Spells[s].SpellCooldown >= 0 || Spells[s].SpellCategoryCooldown >= 0;
queryData << Spells[s].SpellId;
queryData << Spells[s].SpellTrigger;
queryData << int32(Spells[s].SpellCharges);
if (db_data)
{
queryData << uint32(Spells[s].SpellCooldown);
queryData << uint32(Spells[s].SpellCategory);
queryData << uint32(Spells[s].SpellCategoryCooldown);
}
else
{
queryData << uint32(spell->RecoveryTime);
queryData << uint32(spell->GetCategory());
queryData << uint32(spell->CategoryRecoveryTime);
}
}
else
{
queryData << uint32(0);
queryData << uint32(0);
queryData << uint32(0);
queryData << uint32(-1);
queryData << uint32(0);
queryData << uint32(-1);
}
}
queryData << Bonding;
queryData << Description;
queryData << PageText;
queryData << LanguageID;
queryData << PageMaterial;
queryData << StartQuest;
queryData << LockID;
queryData << int32(Material);
queryData << Sheath;
queryData << RandomProperty;
queryData << RandomSuffix;
queryData << Block;
queryData << ItemSet;
queryData << MaxDurability;
queryData << Area;
queryData << Map; // Added in 1.12.x & 2.0.1 client branch
queryData << BagFamily;
queryData << TotemCategory;
for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
{
queryData << Socket[s].Color;
queryData << Socket[s].Content;
}
queryData << socketBonus;
queryData << GemProperties;
queryData << RequiredDisenchantSkill;
queryData << ArmorDamageModifier;
queryData << Duration; // added in 2.4.2.8209, duration (seconds)
queryData << ItemLimitCategory; // WotLK, ItemLimitCategory
queryData << HolidayId; // Holiday.dbc?
}
// Only _static_ data send in this packet !!!
void WorldSession::HandleItemQuerySingleOpcode(WorldPacket& recvData)
{
+11
View File
@@ -4112,6 +4112,12 @@ void Spell::_cast(bool skipCheck)
sScriptMgr->OnSpellCast(this, m_caster, m_spellInfo, skipCheck);
SetExecutedCurrently(false);
// Call CreatureAI hook OnSpellCastFinished
if (m_originalCaster)
if (Creature* caster = m_originalCaster->ToCreature())
if (caster->IsAIEnabled)
caster->AI()->OnSpellCastFinished(GetSpellInfo(), SPELL_FINISHED_SUCCESSFUL_CAST);
}
void Spell::handle_immediate()
@@ -4463,6 +4469,11 @@ void Spell::update(uint32 difftime)
SendChannelUpdate(0);
finish();
// We call the hook here instead of in Spell::finish because we only want to call it for completed channeling. Everything else is handled by interrupts
if (Creature* creatureCaster = m_caster->ToCreature())
if (creatureCaster->IsAIEnabled)
creatureCaster->AI()->OnSpellCastFinished(m_spellInfo, SPELL_FINISHED_CHANNELING_COMPLETE);
}
// Xinef: Dont update channeled target list on last tick, allow auras to update duration properly
// Xinef: Added this strange check because of diffrent update routines for players / creatures
+7
View File
@@ -92,6 +92,13 @@ enum SpellRangeFlag
SPELL_RANGE_RANGED = 2, //hunter range and ranged weapon
};
enum SpellFinishReason : uint8
{
SPELL_FINISHED_SUCCESSFUL_CAST = 0, // spell has sucessfully launched
SPELL_FINISHED_CANCELED = 1, // spell has been canceled (interrupts)
SPELL_FINISHED_CHANNELING_COMPLETE = 2 // spell channeling has been finished
};
struct SpellDestination
{
SpellDestination();
+1
View File
@@ -459,6 +459,7 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<uint32>(CONFIG_ARENA_QUEUE_ANNOUNCER_DETAIL, "Arena.QueueAnnouncer.Detail", 3);
SetConfigValue<bool>(CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN, "OffhandCheckAtSpellUnlearn", true);
SetConfigValue<bool>(CONFIG_CREATURE_REPOSITION_AGAINST_NPCS, "Creature.RepositionAgainstNpcs", true);
SetConfigValue<uint32>(CONFIG_CREATURE_STOP_FOR_PLAYER, "Creature.MovingStopTimeForPlayer", 180000);
SetConfigValue<uint32>(CONFIG_WATER_BREATH_TIMER, "WaterBreath.Timer", 180000, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value > 0; }, "> 0");
+1
View File
@@ -78,6 +78,7 @@ enum ServerConfigs
CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE,
CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY,
CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN,
CONFIG_CREATURE_REPOSITION_AGAINST_NPCS,
CONFIG_VMAP_INDOOR_CHECK,
CONFIG_PET_LOS,
CONFIG_START_CUSTOM_SPELLS,
@@ -2033,12 +2033,8 @@ enum StrengthenAncientsMisc
{
SAY_WALKER_FRIENDLY = 0,
SAY_WALKER_ENEMY = 1,
SAY_LOTHALOR = 0,
SPELL_CREATE_ITEM_BARK = 47550,
SPELL_CONFUSED = 47044,
NPC_LOTHALOR = 26321
};
class spell_q12096_q12092_dummy : public SpellScript
@@ -2082,27 +2078,6 @@ class spell_q12096_q12092_dummy : public SpellScript
}
};
class spell_q12096_q12092_bark : public SpellScript
{
PrepareSpellScript(spell_q12096_q12092_bark);
void HandleDummy(SpellEffIndex /*effIndex*/)
{
Creature* lothalor = GetHitCreature();
if (!lothalor || lothalor->GetEntry() != NPC_LOTHALOR)
return;
lothalor->AI()->Talk(SAY_LOTHALOR);
lothalor->RemoveAura(SPELL_CONFUSED);
lothalor->DespawnOrUnsummon(4000);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_q12096_q12092_bark::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
/*#####
# npc_torturer_lecraft
#####*/
@@ -2320,7 +2295,6 @@ void AddSC_dragonblight()
new npc_spiritual_insight();
new npc_commander_eligor_dawnbringer();
RegisterSpellScript(spell_q12096_q12092_dummy);
RegisterSpellScript(spell_q12096_q12092_bark);
new npc_torturer_lecraft();
RegisterSpellScript(spell_dragonblight_corrosive_spit);
RegisterSpellScript(spell_handover_reins);