Merge branch 'master' into Playerbot
This commit is contained in:
@@ -191,8 +191,26 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
|
||||
{
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
|
||||
{
|
||||
bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER);
|
||||
target = SelectTarget(SelectTargetMethod::Random, 0, spellInfo->GetMaxRange(false), playerOnly);
|
||||
DefaultTargetSelector targetSelector(me, spellInfo->GetMaxRange(false), false, true, 0);
|
||||
target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* target) {
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
|
||||
return false;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer())
|
||||
return false;
|
||||
}
|
||||
return targetSelector(target);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -206,12 +224,30 @@ SpellCastResult UnitAI::DoCast(uint32 spellId)
|
||||
{
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
|
||||
{
|
||||
bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER);
|
||||
float range = spellInfo->GetMaxRange(false);
|
||||
|
||||
DefaultTargetSelector targetSelector(me, range, playerOnly, true, -(int32)spellId);
|
||||
if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM)
|
||||
&& targetSelector(me->GetVictim()))
|
||||
DefaultTargetSelector defaultTargetSelector(me, range, false, true, -(int32)spellId);
|
||||
auto targetSelector = [&](Unit* target) {
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
|
||||
return false;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && target->IsControlledByPlayer())
|
||||
return false;
|
||||
}
|
||||
return defaultTargetSelector(target);
|
||||
};
|
||||
|
||||
if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) && targetSelector(me->GetVictim()))
|
||||
target = me->GetVictim();
|
||||
else
|
||||
target = SelectTarget(SelectTargetMethod::Random, 0, targetSelector);
|
||||
|
||||
@@ -165,9 +165,10 @@ struct PowerUsersSelector : public Acore::unary_function<Unit*, bool>
|
||||
}
|
||||
};
|
||||
|
||||
struct FarthestTargetSelector : public Acore::unary_function<Unit*, bool>
|
||||
// Simple selector based on range and Los
|
||||
struct RangeSelector : public Acore::unary_function<Unit*, bool>
|
||||
{
|
||||
FarthestTargetSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {}
|
||||
RangeSelector(Unit const* unit, float maxDist, bool playerOnly, bool inLos, float minDist = 0.f) : _me(unit), _minDist(minDist), _maxDist(maxDist), _playerOnly(playerOnly), _inLos(inLos) {}
|
||||
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
|
||||
@@ -2506,12 +2506,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT:
|
||||
{
|
||||
std::vector<uint32> waypoints;
|
||||
std::copy_if(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(),
|
||||
std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
|
||||
|
||||
float distanceToClosest = std::numeric_limits<float>::max();
|
||||
WayPoint* closestWp = nullptr;
|
||||
uint32 closestWpId = 0;
|
||||
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
@@ -2519,29 +2515,34 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
if (IsSmart(creature))
|
||||
{
|
||||
for (uint32 wp : waypoints)
|
||||
for (uint32 wp = e.action.startClosestWaypoint.pathId1; wp <= e.action.startClosestWaypoint.pathId2; ++wp)
|
||||
{
|
||||
WPPath* path = sSmartWaypointMgr->GetPath(wp);
|
||||
if (!path || path->empty())
|
||||
continue;
|
||||
|
||||
auto itrWp = path->find(0);
|
||||
auto itrWp = path->find(1);
|
||||
if (itrWp != path->end())
|
||||
{
|
||||
if (WayPoint* wp = itrWp->second)
|
||||
if (WayPoint* wpData = itrWp->second)
|
||||
{
|
||||
float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z);
|
||||
float distToThisPath = creature->GetExactDistSq(wpData->x, wpData->y, wpData->z);
|
||||
if (distToThisPath < distanceToClosest)
|
||||
{
|
||||
distanceToClosest = distToThisPath;
|
||||
closestWp = wp;
|
||||
closestWpId = wp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closestWp)
|
||||
CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true);
|
||||
if (closestWpId)
|
||||
{
|
||||
bool repeat = e.action.startClosestWaypoint.repeat;
|
||||
bool run = e.action.startClosestWaypoint.run;
|
||||
|
||||
CAST_AI(SmartAI, creature->AI())->StartPath(repeat, closestWpId, run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3303,10 +3304,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
if (e.link && e.link != e.event_id)
|
||||
{
|
||||
auto linked = FindLinkedEvent(e.link);
|
||||
if (linked.has_value() && linked.value().get().GetEventType() == SMART_EVENT_LINK)
|
||||
executionStack.emplace_back(SmartScriptFrame{ linked.value(), unit, var0, var1, bvar, spell, gob });
|
||||
if (linked.has_value())
|
||||
{
|
||||
auto& linkedEvent = linked.value().get();
|
||||
if (linkedEvent.GetEventType() == SMART_EVENT_LINK)
|
||||
executionStack.emplace_back(SmartScriptFrame{ linkedEvent, unit, var0, var1, bvar, spell, gob });
|
||||
else
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} found but has wrong type (should be 61, is {}).", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link, linkedEvent.GetEventType());
|
||||
}
|
||||
else
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3509,7 +3516,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
case SMART_TARGET_FARTHEST:
|
||||
if (me)
|
||||
{
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist)))
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos, e.target.farthest.minDist)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3701,10 +3708,12 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
|
||||
if (!units.empty() && baseObject)
|
||||
for (WorldObject* unit : units)
|
||||
if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
|
||||
if (IsPlayer(unit) && !unit->ToPlayer()->IsGameMaster() && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
|
||||
targets.push_back(unit);
|
||||
|
||||
if (e.target.playerRange.maxCount)
|
||||
Acore::Containers::RandomResize(targets, e.target.playerRange.maxCount);
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_TARGET_PLAYER_DISTANCE:
|
||||
@@ -4658,12 +4667,11 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (!targets.empty())
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
if (IsPlayer(target))
|
||||
if (IsPlayer(target) && !target->ToPlayer()->IsGameMaster())
|
||||
playerCount++;
|
||||
}
|
||||
if (playerCount >= e.event.nearPlayer.minCount)
|
||||
ProcessAction(e, unit);
|
||||
|
||||
if (playerCount >= e.event.nearPlayer.minCount)
|
||||
ProcessAction(e, unit);
|
||||
}
|
||||
RecalcTimer(e, e.event.nearPlayer.repeatMin, e.event.nearPlayer.repeatMax);
|
||||
break;
|
||||
@@ -4677,10 +4685,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (!targets.empty())
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
if (IsPlayer(target))
|
||||
if (IsPlayer(target) && !target->ToPlayer()->IsGameMaster())
|
||||
playerCount++;
|
||||
}
|
||||
|
||||
if (playerCount < e.event.nearPlayerNegation.maxCount)
|
||||
ProcessAction(e, unit);
|
||||
|
||||
@@ -806,7 +806,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_REMOVE_POWER: return sizeof(SmartAction::power);
|
||||
case SMART_ACTION_GAME_EVENT_STOP: return sizeof(SmartAction::gameEventStop);
|
||||
case SMART_ACTION_GAME_EVENT_START: return sizeof(SmartAction::gameEventStart);
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::closestWaypointFromList);
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT: return sizeof(SmartAction::startClosestWaypoint);
|
||||
case SMART_ACTION_RISE_UP: return sizeof(SmartAction::moveRandom);
|
||||
case SMART_ACTION_RANDOM_SOUND: return sizeof(SmartAction::randomSound);
|
||||
case SMART_ACTION_SET_CORPSE_DELAY: return sizeof(SmartAction::corpseDelay);
|
||||
@@ -1536,15 +1536,22 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_START_CLOSEST_WAYPOINT:
|
||||
{
|
||||
if (e.action.startClosestWaypoint.pathId1 == 0 || e.action.startClosestWaypoint.pathId2 == 0 || e.action.startClosestWaypoint.pathId2 < e.action.startClosestWaypoint.pathId1)
|
||||
{
|
||||
if (std::all_of(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(), [](uint32 wp) { return wp == 0; }))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid pathId1 or pathId2, it must be greater than 0 and pathId1 > pathId2",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
if (e.action.startClosestWaypoint.repeat > 1 || e.action.startClosestWaypoint.run > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid run ({}) or repeat ({}) parameter, must be 0 or 1.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(),
|
||||
e.action.startClosestWaypoint.repeat, e.action.startClosestWaypoint.run);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_INVOKER_CAST:
|
||||
if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type))
|
||||
{
|
||||
|
||||
@@ -1284,8 +1284,11 @@ struct SmartAction
|
||||
|
||||
struct
|
||||
{
|
||||
std::array<uint32, SMART_ACTION_PARAM_COUNT> wps;
|
||||
} closestWaypointFromList;
|
||||
uint32 pathId1;
|
||||
uint32 pathId2;
|
||||
uint32 repeat;
|
||||
uint32 run;
|
||||
} startClosestWaypoint;
|
||||
|
||||
struct
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace AccountMgr
|
||||
{
|
||||
|
||||
AccountOpResult CreateAccount(std::string username, std::string password)
|
||||
AccountOpResult CreateAccount(std::string username, std::string password, std::string email /*= ""*/)
|
||||
{
|
||||
if (utf8length(username) > MAX_ACCOUNT_STR)
|
||||
return AOR_NAME_TOO_LONG; // username's too long
|
||||
@@ -35,8 +35,12 @@ namespace AccountMgr
|
||||
if (utf8length(password) > MAX_PASS_STR)
|
||||
return AOR_PASS_TOO_LONG; // password's too long
|
||||
|
||||
if (utf8length(email) > MAX_EMAIL_STR)
|
||||
return AOR_EMAIL_TOO_LONG; // email is too long
|
||||
|
||||
Utf8ToUpperOnlyLatin(username);
|
||||
Utf8ToUpperOnlyLatin(password);
|
||||
Utf8ToUpperOnlyLatin(email);
|
||||
|
||||
if (GetId(username))
|
||||
return AOR_NAME_ALREADY_EXIST; // username does already exist
|
||||
@@ -48,6 +52,8 @@ namespace AccountMgr
|
||||
stmt->SetData(1, salt);
|
||||
stmt->SetData(2, verifier);
|
||||
stmt->SetData(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION)));
|
||||
stmt->SetData(4, email);
|
||||
stmt->SetData(5, email);
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ enum AccountOpResult
|
||||
|
||||
namespace AccountMgr
|
||||
{
|
||||
AccountOpResult CreateAccount(std::string username, std::string password);
|
||||
AccountOpResult CreateAccount(std::string username, std::string password, std::string email = "");
|
||||
AccountOpResult DeleteAccount(uint32 accountId);
|
||||
AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword);
|
||||
AccountOpResult ChangePassword(uint32 accountId, std::string newPassword);
|
||||
|
||||
@@ -788,9 +788,7 @@ void Creature::Update(uint32 diff)
|
||||
m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveBackwardsMovementTime -= diff;
|
||||
}
|
||||
|
||||
// Circling the target
|
||||
if (diff >= m_moveCircleMovementTime)
|
||||
@@ -799,9 +797,17 @@ void Creature::Update(uint32 diff)
|
||||
m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveCircleMovementTime -= diff;
|
||||
|
||||
// Periodically check if able to move, if not, extend leash timer
|
||||
if (diff >= m_extendLeashTime)
|
||||
{
|
||||
if (!CanFreeMove())
|
||||
UpdateLeashExtensionTime();
|
||||
m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL;
|
||||
}
|
||||
else
|
||||
m_extendLeashTime -= diff;
|
||||
}
|
||||
|
||||
// Call for assistance if not disabled
|
||||
|
||||
@@ -396,8 +396,10 @@ public:
|
||||
bool IsFreeToMove();
|
||||
static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000;
|
||||
static constexpr uint32 MOVE_BACKWARDS_CHECK_INTERVAL = 2000;
|
||||
static constexpr uint32 EXTEND_LEASH_CHECK_INTERVAL = 3000;
|
||||
uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
|
||||
uint32 m_moveBackwardsMovementTime = MOVE_BACKWARDS_CHECK_INTERVAL;
|
||||
uint32 m_extendLeashTime = EXTEND_LEASH_CHECK_INTERVAL;
|
||||
|
||||
[[nodiscard]] bool HasSwimmingFlagOutOfCombat() const
|
||||
{
|
||||
|
||||
@@ -13642,7 +13642,11 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skill, getRace(), getClass());
|
||||
if (!rcEntry)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character {} has skill {} that does not exist.", GetGUID().ToString(), skill);
|
||||
LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) that is invalid for the race/class combination (Race: {}, Class: {}). Will be deleted.",
|
||||
GetName(), GetGUID().GetCounter(), skill, getRace(), getClass());
|
||||
|
||||
// Mark skill for deletion in the database
|
||||
mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(0, SKILL_DELETED)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -13663,7 +13667,8 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
LOG_ERROR("entities.player", "Character {} has skill {} with value 0. Will be deleted.", GetGUID().ToString(), skill);
|
||||
LOG_ERROR("entities.player", "Player {} (GUID: {}), has skill ({}) with value 0. Will be deleted.",
|
||||
GetName(), GetGUID().GetCounter(), skill);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL);
|
||||
|
||||
|
||||
@@ -65,6 +65,9 @@ public:
|
||||
[[nodiscard]] uint32 GetCurrentTaxiPath() const;
|
||||
uint32 NextTaxiDestination()
|
||||
{
|
||||
if (m_TaxiDestinations.empty())
|
||||
return 0;
|
||||
|
||||
m_TaxiDestinations.pop_front();
|
||||
return GetTaxiDestination();
|
||||
}
|
||||
|
||||
@@ -20114,6 +20114,24 @@ private:
|
||||
AuraType _auraType;
|
||||
};
|
||||
|
||||
class ResetToHomeOrientation : public BasicEvent
|
||||
{
|
||||
public:
|
||||
ResetToHomeOrientation(Creature& self) : _self(self) { }
|
||||
|
||||
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
|
||||
{
|
||||
if (_self.IsInWorld() && _self.FindMap() && _self.IsAlive() && !_self.IsInCombat())
|
||||
{
|
||||
_self.SetFacingTo(_self.GetHomePosition().GetOrientation());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
Creature& _self;
|
||||
};
|
||||
|
||||
void Unit::CastDelayedSpellWithPeriodicAmount(Unit* caster, uint32 spellId, AuraType auraType, int32 addAmount, uint8 effectIndex)
|
||||
{
|
||||
AuraEffect* aurEff = nullptr;
|
||||
@@ -20360,6 +20378,24 @@ void Unit::SetFacingToObject(WorldObject* object)
|
||||
init.Launch();
|
||||
}
|
||||
|
||||
void Unit::SetTimedFacingToObject(WorldObject* object, uint32 time)
|
||||
{
|
||||
// never face when already moving
|
||||
if (!IsStopped() || !time)
|
||||
return;
|
||||
|
||||
/// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is.
|
||||
Movement::MoveSplineInit init(this);
|
||||
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ());
|
||||
init.SetFacing(GetAngle(object)); // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming
|
||||
init.Launch();
|
||||
|
||||
if (Creature* c = ToCreature())
|
||||
c->m_Events.AddEvent(new ResetToHomeOrientation(*c), c->m_Events.CalculateTime(time));
|
||||
else
|
||||
LOG_ERROR("entities.unit", "Unit::SetTimedFacingToObject called on non-creature unit {}. This should never happen.", GetEntry());
|
||||
}
|
||||
|
||||
bool Unit::SetWalk(bool enable)
|
||||
{
|
||||
if (enable == IsWalking())
|
||||
|
||||
@@ -1894,6 +1894,7 @@ public:
|
||||
void SetInFront(WorldObject const* target);
|
||||
void SetFacingTo(float ori);
|
||||
void SetFacingToObject(WorldObject* object);
|
||||
void SetTimedFacingToObject(WorldObject* object, uint32 time); // Reset to home orientation after given time
|
||||
|
||||
bool isInAccessiblePlaceFor(Creature const* c) const;
|
||||
bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const;
|
||||
|
||||
@@ -512,7 +512,7 @@ void GameEventMgr::LoadEventCreatureData()
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
ObjectGuid::LowType guid = fields[0].Get<uint32>();
|
||||
int16 eventId = fields[1].Get<int8>();
|
||||
int16 eventId = fields[1].Get<int16>();
|
||||
|
||||
CreatureData const* data = sObjectMgr->GetCreatureData(guid);
|
||||
if (!data)
|
||||
@@ -562,7 +562,7 @@ void GameEventMgr::LoadEventGameObjectData()
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
ObjectGuid::LowType guid = fields[0].Get<uint32>();
|
||||
int16 eventId = fields[1].Get<int8>();
|
||||
int16 eventId = fields[1].Get<int16>();
|
||||
|
||||
int32 internal_event_id = _gameEvent.size() + eventId - 1;
|
||||
|
||||
@@ -1020,7 +1020,7 @@ void GameEventMgr::LoadEventPoolData()
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 entry = fields[0].Get<uint32>();
|
||||
int16 eventId = fields[1].Get<int8>();
|
||||
int16 eventId = fields[1].Get<int16>();
|
||||
|
||||
int32 internal_event_id = _gameEvent.size() + eventId - 1;
|
||||
|
||||
|
||||
@@ -2317,7 +2317,7 @@ void ObjectMgr::LoadCreatures()
|
||||
data.movementType = fields[15].Get<uint8>();
|
||||
data.spawnMask = fields[16].Get<uint8>();
|
||||
data.phaseMask = fields[17].Get<uint32>();
|
||||
int16 gameEvent = fields[18].Get<int8>();
|
||||
int16 gameEvent = fields[18].Get<int16>();
|
||||
uint32 PoolId = fields[19].Get<uint32>();
|
||||
data.npcflag = fields[20].Get<uint32>();
|
||||
data.unit_flags = fields[21].Get<uint32>();
|
||||
@@ -2709,7 +2709,7 @@ void ObjectMgr::LoadGameobjects()
|
||||
LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: {} Entry: {}) that has wrong spawn mask {} including not supported difficulty modes for map (Id: {}), skip", guid, data.id, data.spawnMask, data.mapid);
|
||||
|
||||
data.phaseMask = fields[15].Get<uint32>();
|
||||
int16 gameEvent = fields[16].Get<int8>();
|
||||
int16 gameEvent = fields[16].Get<int16>();
|
||||
uint32 PoolId = fields[17].Get<uint32>();
|
||||
|
||||
if (data.rotation.x < -1.0f || data.rotation.x > 1.0f)
|
||||
|
||||
@@ -172,8 +172,8 @@ namespace Acore
|
||||
template<class RET_TYPE, int CENTER_VAL>
|
||||
inline RET_TYPE Compute(float x, float y, float size)
|
||||
{
|
||||
int gx = (int)(CENTER_VAL - x / size);
|
||||
int gy = (int)(CENTER_VAL - y / size);
|
||||
int gx = std::max<int>(0, (CENTER_VAL - x / size));
|
||||
int gy = std::max<int>(0, (CENTER_VAL - y / size));
|
||||
|
||||
return RET_TYPE(gx, gy);
|
||||
}
|
||||
|
||||
@@ -331,7 +331,8 @@ enum AcoreStrings
|
||||
LANG_COMMAND_WHISPERON = 285,
|
||||
LANG_COMMAND_WHISPEROFF = 286,
|
||||
LANG_COMMAND_CREATGUIDNOTFOUND = 287,
|
||||
// TICKET STRINGS NEED REWRITE // 288-296 FREE
|
||||
LANG_COMMAND_GONOTENOUGHSPAWNS = 288,
|
||||
// TICKET STRINGS NEED REWRITE // 289-296 FREE
|
||||
|
||||
// END
|
||||
LANG_COMMAND_WANDER_DISTANCE = 297,
|
||||
|
||||
@@ -153,18 +153,20 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
|
||||
MovementInform(owner);
|
||||
}
|
||||
|
||||
if (owner->movespline->Finalized())
|
||||
{ // Mobs should chase you infinitely if you stop and wait every few seconds.
|
||||
i_leashExtensionTimer.Update(time_diff);
|
||||
if (i_leashExtensionTimer.Passed())
|
||||
{
|
||||
i_leashExtensionTimer.Reset(5000);
|
||||
if (cOwner)
|
||||
if (cOwner)
|
||||
{
|
||||
if (owner->movespline->Finalized() && cOwner->IsWithinMeleeRange(target))
|
||||
{ // Mobs should chase you infinitely if you stop and wait every few seconds.
|
||||
i_leashExtensionTimer.Update(time_diff);
|
||||
if (i_leashExtensionTimer.Passed())
|
||||
{
|
||||
i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK));
|
||||
cOwner->UpdateLeashExtensionTime();
|
||||
}
|
||||
}
|
||||
else if (i_recalculateTravel)
|
||||
i_leashExtensionTimer.Reset(cOwner->GetAttackTime(BASE_ATTACK));
|
||||
}
|
||||
else if (i_recalculateTravel)
|
||||
i_leashExtensionTimer.Reset(5000);
|
||||
|
||||
// if the target moved, we have to consider whether to adjust
|
||||
if (!_lastTargetPosition || target->GetPosition() != _lastTargetPosition.value() || mutualChase != _mutualChase || !owner->IsWithinLOSInMap(target))
|
||||
@@ -298,6 +300,7 @@ void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner)
|
||||
i_path = nullptr;
|
||||
_lastTargetPosition.reset();
|
||||
i_recheckDistance.Reset(0);
|
||||
i_leashExtensionTimer.Reset(owner->GetAttackTime(BASE_ATTACK));
|
||||
owner->SetWalk(false);
|
||||
owner->AddUnitState(UNIT_STATE_CHASE);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
class AchievementGlobalMgr;
|
||||
class AchievementMgr;
|
||||
class ArenaTeam;
|
||||
class AuctionEntry;
|
||||
class AuctionHouseMgr;
|
||||
class AuctionHouseObject;
|
||||
class Aura;
|
||||
@@ -98,6 +97,7 @@ enum WeatherState : uint32;
|
||||
struct AchievementCriteriaEntry;
|
||||
struct AchievementEntry;
|
||||
struct AreaTrigger;
|
||||
struct AuctionEntry;
|
||||
struct CompletedAchievementData;
|
||||
struct Condition;
|
||||
struct ConditionSourceInfo;
|
||||
|
||||
@@ -110,6 +110,7 @@ public:
|
||||
uint8 GetCasterLevel() const { return m_casterLevel; }
|
||||
bool CanApplyResilience() const { return m_applyResilience; }
|
||||
float GetPctMods() const { return m_pctMods; }
|
||||
void SetPctMods(float pctMods) { m_pctMods = pctMods; }
|
||||
|
||||
// xinef: stacking
|
||||
uint32 GetAuraGroup() const { return m_auraGroup; }
|
||||
|
||||
@@ -2147,6 +2147,8 @@ uint32 Spell::GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList*
|
||||
retMask &= GRID_MAP_TYPE_MASK_CORPSE | GRID_MAP_TYPE_MASK_PLAYER;
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_GHOSTS))
|
||||
retMask &= GRID_MAP_TYPE_MASK_PLAYER;
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
retMask &= ~GRID_MAP_TYPE_MASK_PLAYER;
|
||||
|
||||
if (condList)
|
||||
retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
|
||||
|
||||
@@ -1863,8 +1863,19 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
else return SPELL_CAST_OK;
|
||||
|
||||
// corpseOwner and unit specific target checks
|
||||
if (AttributesEx3 & SPELL_ATTR3_ONLY_ON_PLAYER && !unitTarget->ToPlayer())
|
||||
return SPELL_FAILED_TARGET_NOT_PLAYER;
|
||||
if (unitTarget->IsPlayer())
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER))
|
||||
return SPELL_FAILED_TARGET_IS_PLAYER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER))
|
||||
return SPELL_FAILED_TARGET_NOT_PLAYER;
|
||||
|
||||
if (HasAttribute(SPELL_ATTR5_NOT_ON_PLAYER_CONTROLLED_NPC) && unitTarget->IsControlledByPlayer())
|
||||
return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED;
|
||||
}
|
||||
|
||||
if (!IsAllowingDeadTarget() && !unitTarget->IsAlive())
|
||||
return SPELL_FAILED_TARGETS_DEAD;
|
||||
|
||||
Reference in New Issue
Block a user