Merge branch 'master' of github.com:azerothcore/azerothcore-wotlk into Playerbot
This commit is contained in:
@@ -82,7 +82,7 @@ protected:
|
||||
Creature* DoSummon(uint32 entry, WorldObject* obj, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
Creature* DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
public:
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
// EnumUtils: DESCRIBE THIS (in CreatureAI::)
|
||||
enum EvadeReason
|
||||
{
|
||||
EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty
|
||||
|
||||
@@ -601,7 +601,7 @@ void SmartAI::MovepointReached(uint32 id)
|
||||
if (mLastWP)
|
||||
{
|
||||
me->SetPosition(mLastWP->x, mLastWP->y, mLastWP->z, me->GetOrientation());
|
||||
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||
me->SetHomePosition(me->GetPosition());
|
||||
}
|
||||
|
||||
if (HasEscortState(SMART_ESCORT_PAUSED))
|
||||
|
||||
@@ -593,9 +593,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
// may be nullptr
|
||||
if (go)
|
||||
{
|
||||
go->CastSpell(target->ToUnit(), e.action.cast.spell);
|
||||
}
|
||||
|
||||
if (!IsUnit(target))
|
||||
continue;
|
||||
@@ -604,29 +602,24 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED));
|
||||
}
|
||||
else if (me && (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)))
|
||||
else if (me)
|
||||
{
|
||||
if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
}
|
||||
// If target has the aura, skip
|
||||
if ((e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) && target->ToUnit()->HasAura(e.action.cast.spell))
|
||||
continue;
|
||||
|
||||
// If the threatlist is a singleton, cancel
|
||||
if (e.action.cast.castFlags & SMARTCAST_THREATLIST_NOT_SINGLE)
|
||||
if (me->GetThreatMgr().GetThreatListSize() <= 1)
|
||||
break;
|
||||
|
||||
TriggerCastFlags triggerFlags = TRIGGERED_NONE;
|
||||
if (e.action.cast.castFlags & SMARTCAST_TRIGGERED)
|
||||
{
|
||||
if (e.action.cast.triggerFlags)
|
||||
{
|
||||
triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
triggerFlags = TRIGGERED_FULL_MASK;
|
||||
}
|
||||
}
|
||||
// If target does not use mana, skip
|
||||
if ((e.action.cast.castFlags & SMARTCAST_TARGET_POWER_MANA) && !target->ToUnit()->GetPower(POWER_MANA))
|
||||
continue;
|
||||
|
||||
// Interrupts current spellcast
|
||||
if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
// Flag usable only if caster has max dist set.
|
||||
if ((e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0)
|
||||
@@ -647,15 +640,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
}
|
||||
|
||||
TriggerCastFlags triggerFlags = TRIGGERED_NONE;
|
||||
if (e.action.cast.castFlags & SMARTCAST_TRIGGERED)
|
||||
{
|
||||
if (e.action.cast.triggerFlags)
|
||||
triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
|
||||
else
|
||||
triggerFlags = TRIGGERED_FULL_MASK;
|
||||
}
|
||||
|
||||
me->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
|
||||
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST: Unit {} casts spell {} on target {} with castflags {}",
|
||||
me->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
|
||||
e.action.cast.spell, target->GetGUID().ToString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2991,6 +2988,47 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_SET_ORIENTATION_TARGET:
|
||||
{
|
||||
switch (e.action.orientationTarget.type)
|
||||
{
|
||||
case 0: // Reset
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingTo((target->ToCreature()->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && target->ToCreature()->GetTransGUID() ? target->ToCreature()->GetTransportHomePosition() : target->ToCreature()->GetHomePosition()).GetOrientation());
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // Target target.o
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingTo(e.target.o);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // Target source
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingToObject(me);
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Target parameters
|
||||
{
|
||||
ObjectVector facingTargets;
|
||||
GetTargets(facingTargets, CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.orientationTarget.targetType, e.action.orientationTarget.targetParam1, e.action.orientationTarget.targetParam2, e.action.orientationTarget.targetParam3, e.action.orientationTarget.targetParam4, 0), unit);
|
||||
|
||||
for (WorldObject* facingTarget : facingTargets)
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingToObject(facingTarget);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
break;
|
||||
@@ -3162,7 +3200,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3174,7 +3212,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3186,7 +3224,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3198,7 +3236,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3785,16 +3823,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (!me || !me->IsEngaged() || !me->GetVictim())
|
||||
return;
|
||||
|
||||
if (me->IsInRange(me->GetVictim(), (float)e.event.rangeRepeat.minRange, (float)e.event.rangeRepeat.maxRange))
|
||||
{
|
||||
if (e.event.rangeRepeat.onlyFireOnRepeat == 2)
|
||||
{
|
||||
e.event.rangeRepeat.onlyFireOnRepeat = 1;
|
||||
RecalcTimer(e, e.event.rangeRepeat.repeatMin, e.event.rangeRepeat.repeatMax);
|
||||
}
|
||||
else
|
||||
ProcessTimedAction(e, e.event.rangeRepeat.repeatMin, e.event.rangeRepeat.repeatMax, me->GetVictim());
|
||||
}
|
||||
if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax))
|
||||
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->GetVictim());
|
||||
else
|
||||
RecalcTimer(e, 1200, 1200); // make it predictable
|
||||
|
||||
@@ -3947,9 +3977,11 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
|
||||
if (Unit* victim = me->GetVictim())
|
||||
{
|
||||
if (!victim->HasInArc(static_cast<float>(M_PI), me))
|
||||
ProcessTimedAction(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax, victim);
|
||||
if (e.event.minMaxRepeat.rangeMax && (me->IsInRange(victim, (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax)))
|
||||
if (!victim->HasInArc(static_cast<float>(M_PI), me))
|
||||
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, victim);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_RECEIVE_EMOTE:
|
||||
@@ -4229,7 +4261,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (IsUnit(target) && me->IsFriendlyTo(target->ToUnit()) && target->ToUnit()->IsAlive() && target->ToUnit()->IsInCombat())
|
||||
{
|
||||
uint32 healthPct = uint32(target->ToUnit()->GetHealthPct());
|
||||
if (healthPct > e.event.friendlyHealthPct.maxHpPct || healthPct < e.event.friendlyHealthPct.minHpPct)
|
||||
if (healthPct > e.event.friendlyHealthPct.hpPct)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -4243,7 +4275,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_TARGET_SELF:
|
||||
case SMART_TARGET_ACTION_INVOKER:
|
||||
unitTarget = DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct);
|
||||
unitTarget = DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, 0, e.event.friendlyHealthPct.hpPct);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -4435,14 +4467,14 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
|
||||
{
|
||||
if (!target || target->IsPet() || target->IsTotem() || !target->IsNonMeleeSpellCast(false, false, true))
|
||||
if (!target || !IsPlayer(target) || !target->IsNonMeleeSpellCast(false, false, true))
|
||||
continue;
|
||||
|
||||
if (e.event.areaCasting.rangeMin && !(me->IsInRange(target, (float)e.event.areaCasting.rangeMin, (float)e.event.areaCasting.rangeMax)))
|
||||
if (!(me->IsInRange(target, (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax)))
|
||||
continue;
|
||||
|
||||
ProcessAction(e, target);
|
||||
RecalcTimer(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMax);
|
||||
RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4463,11 +4495,11 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
|
||||
{
|
||||
if (!(me->IsInRange(target, (float)e.event.areaRange.rangeMin, (float)e.event.areaRange.rangeMax)))
|
||||
if (!(me->IsInRange(target, (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax)))
|
||||
continue;
|
||||
|
||||
ProcessAction(e, target);
|
||||
RecalcTimer(e, e.event.areaRange.repeatMin, e.event.areaRange.repeatMax);
|
||||
RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4487,16 +4519,6 @@ void SmartScript::InitTimer(SmartScriptHolder& e)
|
||||
switch (e.GetEventType())
|
||||
{
|
||||
//set only events which have initial timers
|
||||
case SMART_EVENT_RANGE:
|
||||
// If onlyFireOnRepeat is true set to 2 before entering combat. Will be set back to 1 after entering combat to ignore initial firing.
|
||||
if (e.event.rangeRepeat.onlyFireOnRepeat == 1)
|
||||
e.event.rangeRepeat.onlyFireOnRepeat = 2;
|
||||
// make it predictable
|
||||
RecalcTimer(e, 1200, 1200);
|
||||
break;
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
RecalcTimer(e, e.event.areaRange.min, e.event.areaRange.max);
|
||||
break;
|
||||
case SMART_EVENT_NEAR_PLAYERS:
|
||||
case SMART_EVENT_NEAR_PLAYERS_NEGATION:
|
||||
RecalcTimer(e, e.event.nearPlayer.firstTimer, e.event.nearPlayer.firstTimer);
|
||||
@@ -4504,13 +4526,13 @@ void SmartScript::InitTimer(SmartScriptHolder& e)
|
||||
case SMART_EVENT_UPDATE:
|
||||
case SMART_EVENT_UPDATE_IC:
|
||||
case SMART_EVENT_UPDATE_OOC:
|
||||
case SMART_EVENT_RANGE:
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
case SMART_EVENT_FRIENDLY_HEALTH_PCT:
|
||||
RecalcTimer(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max);
|
||||
break;
|
||||
case SMART_EVENT_OOC_LOS:
|
||||
case SMART_EVENT_IC_LOS:
|
||||
// Xinef: cooldown should be processed AFTER action is done, not before...
|
||||
//RecalcTimer(e, e.event.los.cooldownMin, e.event.los.cooldownMax);
|
||||
//break;
|
||||
case SMART_EVENT_DISTANCE_CREATURE:
|
||||
case SMART_EVENT_DISTANCE_GAMEOBJECT:
|
||||
RecalcTimer(e, e.event.distance.repeat, e.event.distance.repeat);
|
||||
@@ -4519,9 +4541,6 @@ void SmartScript::InitTimer(SmartScriptHolder& e)
|
||||
case SMART_EVENT_NEAR_UNIT_NEGATION:
|
||||
RecalcTimer(e, e.event.nearUnit.timer, e.event.nearUnit.timer);
|
||||
break;
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
RecalcTimer(e, e.event.areaCasting.min, e.event.areaCasting.max);
|
||||
break;
|
||||
default:
|
||||
e.active = true;
|
||||
break;
|
||||
@@ -4550,14 +4569,14 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
|
||||
|
||||
if (e.timer < diff)
|
||||
{
|
||||
// delay spell cast event if another spell is being casted
|
||||
// delay spell cast for another AI tick if another spell is being cast
|
||||
if (e.GetActionType() == SMART_ACTION_CAST)
|
||||
{
|
||||
if (!(e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS))
|
||||
{
|
||||
if (me && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
e.timer = 1;
|
||||
e.timer = 1200;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4566,9 +4585,9 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
|
||||
// Delay flee for assist event if casting
|
||||
if (e.GetActionType() == SMART_ACTION_FLEE_FOR_ASSIST && me && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
e.timer = 1;
|
||||
e.timer = 1200;
|
||||
return;
|
||||
}
|
||||
} // @TODO: Can't these be handled by the action themselves instead? Less expensive
|
||||
|
||||
e.active = true;//activate events with cooldown
|
||||
switch (e.GetEventType())//process ONLY timed events
|
||||
@@ -4809,10 +4828,10 @@ void SmartScript::OnInitialize(WorldObject* obj, AreaTrigger const* at)
|
||||
InitTimer((*i));//calculate timers for first time use
|
||||
if (i->GetEventType() == SMART_EVENT_RANGE && i->GetActionType() == SMART_ACTION_ALLOW_COMBAT_MOVEMENT)
|
||||
{
|
||||
if (i->action.combatMove.move == 1 && i->event.rangeRepeat.minRange > minEnableDist)
|
||||
minEnableDist = i->event.rangeRepeat.minRange;
|
||||
else if (i->action.combatMove.move == 0 && (i->event.rangeRepeat.maxRange < maxDisableDist || maxDisableDist == 0))
|
||||
maxDisableDist = i->event.rangeRepeat.maxRange;
|
||||
if (i->action.combatMove.move == 1 && i->event.minMaxRepeat.rangeMin > minEnableDist)
|
||||
minEnableDist = i->event.minMaxRepeat.rangeMin;
|
||||
else if (i->action.combatMove.move == 0 && (i->event.minMaxRepeat.rangeMax < maxDisableDist || maxDisableDist == 0))
|
||||
maxDisableDist = i->event.minMaxRepeat.rangeMax;
|
||||
}
|
||||
|
||||
// Xinef: if smartcast combat move flag is present
|
||||
|
||||
@@ -264,29 +264,14 @@ void SmartAIMgr::LoadSmartAIFromDB()
|
||||
case SMART_EVENT_FRIENDLY_MISSING_BUFF:
|
||||
case SMART_EVENT_HAS_AURA:
|
||||
case SMART_EVENT_TARGET_BUFFED:
|
||||
case SMART_EVENT_RANGE:
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
if (temp.event.minMaxRepeat.repeatMin == 0 && temp.event.minMaxRepeat.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_RANGE:
|
||||
if (temp.event.rangeRepeat.repeatMin == 0 && temp.event.rangeRepeat.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
// Will only work properly if value is 0 or 1
|
||||
if (temp.event.rangeRepeat.onlyFireOnRepeat > 1)
|
||||
temp.event.rangeRepeat.onlyFireOnRepeat = 1;
|
||||
break;
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
if (temp.event.areaRange.repeatMin == 0 && temp.event.areaRange.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_VICTIM_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
if (temp.event.minMaxRepeat.min == 0 && temp.event.minMaxRepeat.max == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
if (temp.event.areaCasting.repeatMin == 0 && temp.event.areaCasting.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_FRIENDLY_IS_CC:
|
||||
if (temp.event.friendlyCC.repeatMin == 0 && temp.event.friendlyCC.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
@@ -506,7 +491,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
|
||||
case SMART_EVENT_DEATH: return NO_PARAMS;
|
||||
case SMART_EVENT_EVADE: return NO_PARAMS;
|
||||
case SMART_EVENT_SPELLHIT: return sizeof(SmartEvent::spellHit);
|
||||
case SMART_EVENT_RANGE: return sizeof(SmartEvent::rangeRepeat);
|
||||
case SMART_EVENT_RANGE: return sizeof(SmartEvent::minMaxRepeat);
|
||||
case SMART_EVENT_OOC_LOS: return sizeof(SmartEvent::los);
|
||||
case SMART_EVENT_RESPAWN: return sizeof(SmartEvent::respawn);
|
||||
case SMART_EVENT_TARGET_HEALTH_PCT: return sizeof(SmartEvent::minMaxRepeat);
|
||||
@@ -564,7 +549,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
|
||||
case SMART_EVENT_GOSSIP_HELLO: return sizeof(SmartEvent::gossipHello);
|
||||
case SMART_EVENT_FOLLOW_COMPLETED: return NO_PARAMS;
|
||||
case SMART_EVENT_EVENT_PHASE_CHANGE: return sizeof(SmartEvent::eventPhaseChange);
|
||||
case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::behindTarget);
|
||||
case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::minMaxRepeat);
|
||||
case SMART_EVENT_GAME_EVENT_START: return sizeof(SmartEvent::gameEvent);
|
||||
case SMART_EVENT_GAME_EVENT_END: return sizeof(SmartEvent::gameEvent);
|
||||
case SMART_EVENT_GO_STATE_CHANGED: return sizeof(SmartEvent::goStateChanged);
|
||||
@@ -584,8 +569,8 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
|
||||
case SMART_EVENT_NEAR_PLAYERS_NEGATION: return sizeof(SmartEvent::nearPlayerNegation);
|
||||
case SMART_EVENT_NEAR_UNIT: return sizeof(SmartEvent::nearUnit);
|
||||
case SMART_EVENT_NEAR_UNIT_NEGATION: return sizeof(SmartEvent::nearUnitNegation);
|
||||
case SMART_EVENT_AREA_CASTING: return sizeof(SmartEvent::areaCasting);
|
||||
case SMART_EVENT_AREA_RANGE: return sizeof(SmartEvent::areaRange);
|
||||
case SMART_EVENT_AREA_CASTING: return sizeof(SmartEvent::minMaxRepeat);
|
||||
case SMART_EVENT_AREA_RANGE: return sizeof(SmartEvent::minMaxRepeat);
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event {} with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetEventType());
|
||||
@@ -781,6 +766,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_SUMMON_RADIAL: return sizeof(SmartAction::radialSummon);
|
||||
case SMART_ACTION_PLAY_SPELL_VISUAL: return sizeof(SmartAction::spellVisual);
|
||||
case SMART_ACTION_FOLLOW_GROUP: return sizeof(SmartAction::followGroup);
|
||||
case SMART_ACTION_SET_ORIENTATION_TARGET: return sizeof(SmartAction::orientationTarget);
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
@@ -963,21 +949,17 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_RANGE:
|
||||
if (!IsMinMaxValid(e, e.event.rangeRepeat.minRange, e.event.rangeRepeat.maxRange))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.rangeRepeat.repeatMin, e.event.rangeRepeat.repeatMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
if (!IsMinMaxValid(e, e.event.areaRange.min, e.event.areaRange.max))
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
case SMART_EVENT_RANGE:
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaRange.repeatMin, e.event.areaRange.repeatMax))
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaRange.rangeMin, e.event.areaRange.rangeMax))
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.rangeMin, e.event.minMaxRepeat.rangeMax))
|
||||
return false;
|
||||
|
||||
break;
|
||||
@@ -1070,16 +1052,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (!IsMinMaxValid(e, e.event.targetCasting.repeatMin, e.event.targetCasting.repeatMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
if (!IsMinMaxValid(e, e.event.areaCasting.min, e.event.areaCasting.max))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMax))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaCasting.rangeMin, e.event.areaCasting.rangeMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_PASSENGER_BOARDED:
|
||||
case SMART_EVENT_PASSENGER_REMOVED:
|
||||
if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax))
|
||||
@@ -1185,10 +1157,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_GAME_EVENT_START:
|
||||
case SMART_EVENT_GAME_EVENT_END:
|
||||
{
|
||||
@@ -1207,10 +1175,13 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_FRIENDLY_HEALTH_PCT:
|
||||
if (!IsMinMaxValid(e, e.event.friendlyHealthPct.min, e.event.friendlyHealthPct.max))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax))
|
||||
return false;
|
||||
|
||||
if (e.event.friendlyHealthPct.maxHpPct > 100 || e.event.friendlyHealthPct.minHpPct > 100)
|
||||
if (e.event.friendlyHealthPct.hpPct > 100)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
@@ -1971,6 +1942,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_SUMMON_RADIAL:
|
||||
case SMART_ACTION_PLAY_SPELL_VISUAL:
|
||||
case SMART_ACTION_FOLLOW_GROUP:
|
||||
case SMART_ACTION_SET_ORIENTATION_TARGET:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -124,7 +124,7 @@ enum SMART_EVENT
|
||||
SMART_EVENT_DEATH = 6, // NONE
|
||||
SMART_EVENT_EVADE = 7, // NONE
|
||||
SMART_EVENT_SPELLHIT = 8, // SpellID, School, CooldownMin, CooldownMax
|
||||
SMART_EVENT_RANGE = 9, // minRange, maxRange, repeatMin, repeatMax, onlyFireOnRepeat
|
||||
SMART_EVENT_RANGE = 9, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
SMART_EVENT_OOC_LOS = 10, // HostilityMode, MaxRnage, CooldownMin, CooldownMax, PlayerOnly
|
||||
SMART_EVENT_RESPAWN = 11, // type, MapId, ZoneId
|
||||
SMART_EVENT_TARGET_HEALTH_PCT = 12, // HPMin%, HPMax%, RepeatMin, RepeatMax
|
||||
@@ -182,14 +182,14 @@ enum SMART_EVENT
|
||||
SMART_EVENT_GOSSIP_HELLO = 64, // event_para_1 (only) 0 = no filter set, always execute action, 1 = GossipHello only filter set, skip action if reportUse, 2 = reportUse only filter set, skip action if GossipHello
|
||||
SMART_EVENT_FOLLOW_COMPLETED = 65, // none
|
||||
SMART_EVENT_EVENT_PHASE_CHANGE = 66, // event phase mask (<= SMART_EVENT_PHASE_ALL)
|
||||
SMART_EVENT_IS_BEHIND_TARGET = 67, // cooldownMin, CooldownMax
|
||||
SMART_EVENT_IS_BEHIND_TARGET = 67, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
SMART_EVENT_GAME_EVENT_START = 68, // game_event.Entry
|
||||
SMART_EVENT_GAME_EVENT_END = 69, // game_event.Entry
|
||||
SMART_EVENT_GO_STATE_CHANGED = 70, // go state
|
||||
SMART_EVENT_GO_EVENT_INFORM = 71, // eventId
|
||||
SMART_EVENT_ACTION_DONE = 72, // eventId (SharedDefines.EventId)
|
||||
SMART_EVENT_ON_SPELLCLICK = 73, // clicker (unit)
|
||||
SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // minHpPct, maxHpPct, repeatMin, repeatMax
|
||||
SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // min, max, repeatMin, repeatMax, hpPct, range
|
||||
SMART_EVENT_DISTANCE_CREATURE = 75, // guid, entry, distance, repeat
|
||||
SMART_EVENT_DISTANCE_GAMEOBJECT = 76, // guid, entry, distance, repeat
|
||||
SMART_EVENT_COUNTER_SET = 77, // id, value, cooldownMin, cooldownMax
|
||||
@@ -210,8 +210,8 @@ enum SMART_EVENT
|
||||
SMART_EVENT_NEAR_PLAYERS_NEGATION = 102, // max, radius, first timer, repeatMin, repeatMax
|
||||
SMART_EVENT_NEAR_UNIT = 103, // type (0: creature 1: gob), entry, count, range, timer
|
||||
SMART_EVENT_NEAR_UNIT_NEGATION = 104, // type (0: creature 1: gob), entry, count, range, timer
|
||||
SMART_EVENT_AREA_CASTING = 105, // min, max, repeatMin, repeatMax, range
|
||||
SMART_EVENT_AREA_RANGE = 106, // min, max, repeatMin, repeatMax, range
|
||||
SMART_EVENT_AREA_CASTING = 105, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
SMART_EVENT_AREA_RANGE = 106, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
|
||||
SMART_EVENT_AC_END = 107
|
||||
};
|
||||
@@ -230,17 +230,10 @@ struct SmartEvent
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 rangeMin;
|
||||
uint32 rangeMax;
|
||||
} minMaxRepeat;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 minRange;
|
||||
uint32 maxRange;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 onlyFireOnRepeat;
|
||||
} rangeRepeat;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 cooldownMin;
|
||||
@@ -430,12 +423,6 @@ struct SmartEvent
|
||||
uint32 phasemask;
|
||||
} eventPhaseChange;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 cooldownMin;
|
||||
uint32 cooldownMax;
|
||||
} behindTarget;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 gameEventId;
|
||||
@@ -458,10 +445,11 @@ struct SmartEvent
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 minHpPct;
|
||||
uint32 maxHpPct;
|
||||
uint32 min;
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 hpPct;
|
||||
uint32 radius;
|
||||
} friendlyHealthPct;
|
||||
|
||||
@@ -517,26 +505,6 @@ struct SmartEvent
|
||||
uint32 timer;
|
||||
} nearUnitNegation;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 min;
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 rangeMin;
|
||||
uint32 rangeMax;
|
||||
} areaCasting;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 min;
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 rangeMin;
|
||||
uint32 rangeMax;
|
||||
} areaRange;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 param1;
|
||||
@@ -743,8 +711,9 @@ enum SMART_ACTION
|
||||
SMART_ACTION_SUMMON_RADIAL = 228, // summonEntry, summonDuration, repetitions, startAngle, stepAngle, dist
|
||||
SMART_ACTION_PLAY_SPELL_VISUAL = 229, // visualId, visualIdImpact
|
||||
SMART_ACTION_FOLLOW_GROUP = 230, // followState, followType, dist
|
||||
SMART_ACTION_SET_ORIENTATION_TARGET = 231, // type, target_type, target_param1, target_param2, target_param3, target_param4
|
||||
|
||||
SMART_ACTION_AC_END = 231, // placeholder
|
||||
SMART_ACTION_AC_END = 232, // placeholder
|
||||
};
|
||||
|
||||
enum class SmartActionSummonCreatureFlags
|
||||
@@ -1453,6 +1422,16 @@ struct SmartAction
|
||||
uint32 followType;
|
||||
uint32 dist;
|
||||
} followGroup;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 type;
|
||||
uint32 targetType;
|
||||
uint32 targetParam1;
|
||||
uint32 targetParam2;
|
||||
uint32 targetParam3;
|
||||
uint32 targetParam4;
|
||||
} orientationTarget;
|
||||
//! Note for any new future actions
|
||||
//! All parameters must have type uint32
|
||||
|
||||
@@ -1484,10 +1463,10 @@ enum SMARTAI_TARGETS
|
||||
SMART_TARGET_NONE = 0, // NONE
|
||||
SMART_TARGET_SELF = 1, // Self cast
|
||||
SMART_TARGET_VICTIM = 2, // Our current target (ie: highest aggro)
|
||||
SMART_TARGET_HOSTILE_SECOND_AGGRO = 3, // Second highest aggro, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_LAST_AGGRO = 4, // Dead last on aggro, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_RANDOM = 5, // Just any random target on our threat list, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_RANDOM_NOT_TOP = 6, // Any random target except top threat, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_SECOND_AGGRO = 3, // Second highest aggro, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_HOSTILE_LAST_AGGRO = 4, // Dead last on aggro, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_HOSTILE_RANDOM = 5, // Just any random target on our threat list, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_HOSTILE_RANDOM_NOT_TOP = 6, // Any random target except top threat, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_ACTION_INVOKER = 7, // Unit who caused this Event to occur
|
||||
SMART_TARGET_POSITION = 8, // use xyz from event params
|
||||
SMART_TARGET_CREATURE_RANGE = 9, // CreatureEntry(0any), minDist, maxDist, alive(0 - both, 1 - alive, 2 - dead)
|
||||
@@ -1551,6 +1530,7 @@ struct SmartTarget
|
||||
uint32 maxDist;
|
||||
SAIBool playerOnly;
|
||||
uint32 powerType;
|
||||
uint32 aura;
|
||||
} hostileRandom;
|
||||
|
||||
struct
|
||||
@@ -1864,16 +1844,16 @@ const uint32 SmartAIEventMask[SMART_EVENT_AC_END][2] =
|
||||
|
||||
enum SmartEventFlags
|
||||
{
|
||||
SMART_EVENT_FLAG_NOT_REPEATABLE = 0x001, //Event can not repeat
|
||||
SMART_EVENT_FLAG_DIFFICULTY_0 = 0x002, //Event only occurs in instance difficulty 0
|
||||
SMART_EVENT_FLAG_DIFFICULTY_1 = 0x004, //Event only occurs in instance difficulty 1
|
||||
SMART_EVENT_FLAG_DIFFICULTY_2 = 0x008, //Event only occurs in instance difficulty 2
|
||||
SMART_EVENT_FLAG_DIFFICULTY_3 = 0x010, //Event only occurs in instance difficulty 3
|
||||
SMART_EVENT_FLAG_NOT_REPEATABLE = 0x001, // Event can not repeat
|
||||
SMART_EVENT_FLAG_DIFFICULTY_0 = 0x002, // Event only occurs in instance difficulty 0
|
||||
SMART_EVENT_FLAG_DIFFICULTY_1 = 0x004, // Event only occurs in instance difficulty 1
|
||||
SMART_EVENT_FLAG_DIFFICULTY_2 = 0x008, // Event only occurs in instance difficulty 2
|
||||
SMART_EVENT_FLAG_DIFFICULTY_3 = 0x010, // Event only occurs in instance difficulty 3
|
||||
SMART_EVENT_FLAG_RESERVED_5 = 0x020,
|
||||
SMART_EVENT_FLAG_RESERVED_6 = 0x040,
|
||||
SMART_EVENT_FLAG_DEBUG_ONLY = 0x080, //Event only occurs in debug build
|
||||
SMART_EVENT_FLAG_DONT_RESET = 0x100, //Event will not reset in SmartScript::OnReset()
|
||||
SMART_EVENT_FLAG_WHILE_CHARMED = 0x200, //Event occurs even if AI owner is charmed
|
||||
SMART_EVENT_FLAG_DEBUG_ONLY = 0x080, // Event only occurs in debug build
|
||||
SMART_EVENT_FLAG_DONT_RESET = 0x100, // Event will not reset in SmartScript::OnReset()
|
||||
SMART_EVENT_FLAG_WHILE_CHARMED = 0x200, // Event occurs even if AI owner is charmed
|
||||
|
||||
SMART_EVENT_FLAG_DIFFICULTY_ALL = (SMART_EVENT_FLAG_DIFFICULTY_0 | SMART_EVENT_FLAG_DIFFICULTY_1 | SMART_EVENT_FLAG_DIFFICULTY_2 | SMART_EVENT_FLAG_DIFFICULTY_3),
|
||||
SMART_EVENT_FLAGS_ALL = (SMART_EVENT_FLAG_NOT_REPEATABLE | SMART_EVENT_FLAG_DIFFICULTY_ALL | SMART_EVENT_FLAG_RESERVED_5 | SMART_EVENT_FLAG_RESERVED_6 | SMART_EVENT_FLAG_DEBUG_ONLY | SMART_EVENT_FLAG_DONT_RESET | SMART_EVENT_FLAG_WHILE_CHARMED)
|
||||
@@ -1881,14 +1861,15 @@ enum SmartEventFlags
|
||||
|
||||
enum SmartCastFlags
|
||||
{
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x01, //Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time)
|
||||
//CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range
|
||||
//CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range
|
||||
//CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x40, //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
SMARTCAST_THREATLIST_NOT_SINGLE = 0x80 //Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
|
||||
//CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
|
||||
//CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
|
||||
//CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
|
||||
SMARTCAST_TARGET_POWER_MANA = 0x100 // Only cast if the target has power type mana (e.g. Mana Drain)
|
||||
};
|
||||
|
||||
enum SmartFollowType
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Acore::Impl::EnumUtilsImpl
|
||||
{
|
||||
|
||||
/****************************************************************************\
|
||||
|* data for enum 'CreatureAI::EvadeReason' in 'CreatureAI.h' auto-generated *|
|
||||
\****************************************************************************/
|
||||
template <>
|
||||
AC_API_EXPORT EnumText EnumUtils<CreatureAI::EvadeReason>::ToString(CreatureAI::EvadeReason value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case CreatureAI::EVADE_REASON_NO_HOSTILES: return { "EVADE_REASON_NO_HOSTILES", "EVADE_REASON_NO_HOSTILES", "the creature's threat list is empty" };
|
||||
case CreatureAI::EVADE_REASON_BOUNDARY: return { "EVADE_REASON_BOUNDARY", "EVADE_REASON_BOUNDARY", "the creature has moved outside its evade boundary" };
|
||||
case CreatureAI::EVADE_REASON_SEQUENCE_BREAK: return { "EVADE_REASON_SEQUENCE_BREAK", "EVADE_REASON_SEQUENCE_BREAK", "this is a boss and the pre-requisite encounters for engaging it are not defeated yet" };
|
||||
case CreatureAI::EVADE_REASON_NO_PATH: return { "EVADE_REASON_NO_PATH", "EVADE_REASON_NO_PATH", "the creature was unable to reach its target for over 5 seconds" };
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<CreatureAI::EvadeReason>::Count() { return 4; }
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT CreatureAI::EvadeReason EnumUtils<CreatureAI::EvadeReason>::FromIndex(size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return CreatureAI::EVADE_REASON_NO_HOSTILES;
|
||||
case 1: return CreatureAI::EVADE_REASON_BOUNDARY;
|
||||
case 2: return CreatureAI::EVADE_REASON_SEQUENCE_BREAK;
|
||||
case 3: return CreatureAI::EVADE_REASON_NO_PATH;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<CreatureAI::EvadeReason>::ToIndex(CreatureAI::EvadeReason value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case CreatureAI::EVADE_REASON_NO_HOSTILES: return 0;
|
||||
case CreatureAI::EVADE_REASON_BOUNDARY: return 1;
|
||||
case CreatureAI::EVADE_REASON_SEQUENCE_BREAK: return 2;
|
||||
case CreatureAI::EVADE_REASON_NO_PATH: return 3;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
break;
|
||||
default:
|
||||
if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT)
|
||||
@@ -757,7 +758,12 @@ void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, C
|
||||
data << uint32(timedCompleted ? 0 : 1); // 1 is for keeping the counter at 0 in client
|
||||
data.AppendPackedTime(progress->date);
|
||||
data << uint32(timeElapsed); // time elapsed in seconds
|
||||
data << uint32(0); // unk
|
||||
|
||||
if (sAchievementMgr->IsAverageCriteria(entry))
|
||||
data << uint32(GameTime::GetGameTime().count() - GetPlayer()->GetCreationTime().count()); // for average achievements
|
||||
else
|
||||
data << uint32(timeElapsed); // time elapsed in seconds
|
||||
|
||||
GetPlayer()->SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
@@ -881,6 +887,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
|
||||
@@ -1147,6 +1154,21 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
{
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if (!miscValue1)
|
||||
continue;
|
||||
|
||||
Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : sMapMgr->FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
|
||||
if (!map || !map->IsDungeon())
|
||||
continue;
|
||||
|
||||
if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->complete_raid.groupSize)
|
||||
continue;
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if (!miscValue1)
|
||||
@@ -1732,6 +1754,16 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
{
|
||||
// those requirements couldn't be found in the dbc
|
||||
AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
|
||||
if (!data || !data->Meets(GetPlayer(), nullptr))
|
||||
continue;
|
||||
|
||||
SetCriteriaProgress(achievementCriteria, 1);
|
||||
break;
|
||||
}
|
||||
// std case: not exist in DBC, not triggered in code as result
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
|
||||
@@ -1741,8 +1773,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING:
|
||||
break;
|
||||
// FIXME: not triggered in code as result, need to implement
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
|
||||
break; // Not implemented yet :(
|
||||
}
|
||||
@@ -1907,11 +1937,14 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
|
||||
return true;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
|
||||
return achievementCriteria->win_arena.count && progress->counter >= achievementCriteria->win_arena.count;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
return true;
|
||||
// handle all statistic-only criteria here
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
|
||||
@@ -1936,6 +1969,7 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
|
||||
@@ -2344,7 +2378,11 @@ void AchievementMgr::BuildAllDataPacket(WorldPacket* data) const
|
||||
*data << uint32(0); /// @todo: This should be 1 if it is a failed timed criteria
|
||||
data->AppendPackedTime(iter->second.date);
|
||||
*data << uint32(now - iter->second.date);
|
||||
*data << uint32(now - iter->second.date);
|
||||
|
||||
if (sAchievementMgr->IsAverageCriteria(sAchievementCriteriaStore.LookupEntry(iter->first)))
|
||||
*data << uint32(now - GetPlayer()->GetCreationTime().count()); // for average achievements
|
||||
else
|
||||
*data << uint32(now - iter->second.date);
|
||||
}
|
||||
|
||||
*data << int32(-1);
|
||||
@@ -2433,6 +2471,19 @@ bool AchievementGlobalMgr::IsStatisticAchievement(AchievementEntry const* achiev
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::IsAverageCriteria(AchievementCriteriaEntry const* criteria) const
|
||||
{
|
||||
if ((sAchievementStore.LookupEntry(criteria->referredAchievement))->flags & ACHIEVEMENT_FLAG_AVERAGE)
|
||||
return true;
|
||||
|
||||
if (AchievementEntryList const* achRefList = GetAchievementByReferencedId(criteria->referredAchievement))
|
||||
for (AchievementEntryList::const_iterator itr = achRefList->begin(); itr != achRefList->end(); ++itr)
|
||||
if ((*itr)->flags & ACHIEVEMENT_FLAG_AVERAGE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const
|
||||
{
|
||||
auto itr = _allCompletedAchievements.find(achievement->ID);
|
||||
@@ -2724,6 +2775,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
|
||||
|
||||
@@ -330,6 +330,7 @@ public:
|
||||
|
||||
bool IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const;
|
||||
bool IsStatisticAchievement(AchievementEntry const* achievement) const;
|
||||
bool IsAverageCriteria(AchievementCriteriaEntry const* criteria) const;
|
||||
|
||||
[[nodiscard]] AchievementCriteriaEntryList const* GetAchievementCriteriaByType(AchievementCriteriaTypes type) const
|
||||
{
|
||||
|
||||
@@ -761,6 +761,9 @@ bool AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
|
||||
}
|
||||
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
if (!Aentry)
|
||||
return false;
|
||||
|
||||
// Skip expired auctions
|
||||
if (Aentry->expire_time < curTime.count())
|
||||
{
|
||||
|
||||
@@ -122,4 +122,4 @@ protected:
|
||||
uint32 HealingDone = 0;
|
||||
};
|
||||
|
||||
#endif // TRINITY_BATTLEGROUND_SCORE_H
|
||||
#endif // _BATTLEGROUND_SCORE_H
|
||||
|
||||
@@ -42,7 +42,7 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
|
||||
case CREATURE_FLAG_EXTRA_NO_TAUNT: return { "CREATURE_FLAG_EXTRA_NO_TAUNT", "CREATURE_FLAG_EXTRA_NO_TAUNT", "creature is immune to taunt auras and 'attack me' effects" };
|
||||
case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return { "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "creature won't update movement flags" };
|
||||
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" };
|
||||
case CREATURE_FLAG_EXTRA_UNUSED_12: return { "CREATURE_FLAG_EXTRA_UNUSED_12", "CREATURE_FLAG_EXTRA_UNUSED_12", "TODO: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
|
||||
case CREATURE_FLAG_EXTRA_UNUSED_12: return { "CREATURE_FLAG_EXTRA_UNUSED_12", "CREATURE_FLAG_EXTRA_UNUSED_12", "/ @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
|
||||
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return { "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "" };
|
||||
case CREATURE_FLAG_EXTRA_WORLDEVENT: return { "CREATURE_FLAG_EXTRA_WORLDEVENT", "CREATURE_FLAG_EXTRA_WORLDEVENT", "custom flag for world event creatures (left room for merging)" };
|
||||
@@ -55,10 +55,10 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
|
||||
case CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ: return { "CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ", "CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ", "creature does not need to take player damage for kill credit" };
|
||||
case CREATURE_FLAG_EXTRA_AVOID_AOE: return { "CREATURE_FLAG_EXTRA_AVOID_AOE", "CREATURE_FLAG_EXTRA_AVOID_AOE", "pussywizard: ignored by aoe attacks (for icc blood prince council npc - Dark Nucleus)" };
|
||||
case CREATURE_FLAG_EXTRA_NO_DODGE: return { "CREATURE_FLAG_EXTRA_NO_DODGE", "CREATURE_FLAG_EXTRA_NO_DODGE", "xinef: target cannot dodge" };
|
||||
case CREATURE_FLAG_EXTRA_MODULE: return { "CREATURE_FLAG_EXTRA_MODULE", "CREATURE_FLAG_EXTRA_MODULE", "Used by module creatures to avoid blizzlike checks." };
|
||||
case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return { "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "Creature does not call for assistance on initial aggro", "" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS: return { "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "Prevents creature from responding to assistance calls", "" };
|
||||
case CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI: return { "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "Creature entry SAI won't be overriden by GUID SAI", "" };
|
||||
case CREATURE_FLAG_EXTRA_MODULE: return { "CREATURE_FLAG_EXTRA_MODULE", "CREATURE_FLAG_EXTRA_MODULE", "" };
|
||||
case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return { "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "Prevent creatures from calling for assistance on initial aggro" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS: return { "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "Prevents creature from responding to assistance calls" };
|
||||
case CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI: return { "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "Load both ENTRY and GUID specific SAI" };
|
||||
case CREATURE_FLAG_EXTRA_DUNGEON_BOSS: return { "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING: return { "CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING", "CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING", "creature ignore pathfinding" };
|
||||
case CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK: return { "CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK", "CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK", "creature is immune to knockback effects" };
|
||||
|
||||
@@ -1725,7 +1725,10 @@ void GameObject::Use(Unit* user)
|
||||
player->SendCinematicStart(info->camera.cinematicId);
|
||||
|
||||
if (info->camera.eventID)
|
||||
{
|
||||
GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this);
|
||||
EventInform(info->camera.eventID);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -196,10 +196,10 @@ struct Position
|
||||
|
||||
float GetRelativeAngle(const Position* pos) const
|
||||
{
|
||||
return GetAngle(pos) - m_orientation;
|
||||
return NormalizeOrientation(GetAngle(pos) - m_orientation);
|
||||
}
|
||||
|
||||
[[nodiscard]] float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
|
||||
[[nodiscard]] float GetRelativeAngle(float x, float y) const { return NormalizeOrientation(GetAngle(x, y) - m_orientation); }
|
||||
[[nodiscard]] float ToAbsoluteAngle(float relAngle) const { return NormalizeOrientation(relAngle + m_orientation); }
|
||||
|
||||
void GetSinCos(float x, float y, float& vsin, float& vcos) const;
|
||||
|
||||
@@ -384,6 +384,8 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
||||
|
||||
_activeCheats = CHEAT_NONE;
|
||||
|
||||
m_creationTime = 0s;
|
||||
|
||||
_cinematicMgr = new CinematicMgr(this);
|
||||
|
||||
m_achievementMgr = new AchievementMgr(this);
|
||||
@@ -8043,6 +8045,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
// need know merged fishing/corpse loot type for achievements
|
||||
loot->loot_type = loot_type;
|
||||
|
||||
if (!sScriptMgr->OnAllowedToLootContainerCheck(this, guid))
|
||||
{
|
||||
SendLootError(guid, LOOT_ERROR_DIDNT_KILL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (permission != NONE_PERMISSION)
|
||||
{
|
||||
SetLootGUID(guid);
|
||||
@@ -13268,6 +13276,8 @@ void Player::SetTitle(CharTitlesEntry const* title, bool lost)
|
||||
data << uint32(title->bit_index);
|
||||
data << uint32(lost ? 0 : 1); // 1 - earned, 0 - lost
|
||||
GetSession()->SendPacket(&data);
|
||||
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK);
|
||||
}
|
||||
|
||||
uint32 Player::GetRuneBaseCooldown(uint8 index, bool skipGrace)
|
||||
@@ -13544,8 +13554,13 @@ uint32 Player::CalculateTalentsPoints() const
|
||||
return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT));
|
||||
}
|
||||
|
||||
bool Player::canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell) const
|
||||
bool Player::canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell)
|
||||
{
|
||||
if (!sScriptMgr->OnCanPlayerFlyInZone(this, mapid,zone,bySpell))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// continent checked in SpellInfo::CheckLocation at cast and area update
|
||||
uint32 v_map = GetVirtualMapForMapAndZone(mapid, zone);
|
||||
if (v_map == 571 && !bySpell->HasAttribute(SPELL_ATTR7_IGNORES_COLD_WEATHER_FLYING_REQUIREMENT))
|
||||
|
||||
@@ -2299,7 +2299,7 @@ public:
|
||||
}
|
||||
void HandleFall(MovementInfo const& movementInfo);
|
||||
|
||||
[[nodiscard]] bool canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell) const;
|
||||
[[nodiscard]] bool canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell);
|
||||
|
||||
void SetClientControl(Unit* target, bool allowMove, bool packetOnly = false);
|
||||
|
||||
@@ -2495,6 +2495,9 @@ public:
|
||||
void CompletedAchievement(AchievementEntry const* entry);
|
||||
[[nodiscard]] AchievementMgr* GetAchievementMgr() const { return m_achievementMgr; }
|
||||
|
||||
void SetCreationTime(Seconds creationTime) { m_creationTime = creationTime; }
|
||||
[[nodiscard]] Seconds GetCreationTime() const { return m_creationTime; }
|
||||
|
||||
[[nodiscard]] bool HasTitle(uint32 bitIndex) const;
|
||||
bool HasTitle(CharTitlesEntry const* title) const { return HasTitle(title->bit_index); }
|
||||
void SetTitle(CharTitlesEntry const* title, bool lost = false);
|
||||
@@ -2951,6 +2954,8 @@ private:
|
||||
bool _wasOutdoor;
|
||||
|
||||
PlayerSettingMap m_charSettingsMap;
|
||||
|
||||
Seconds m_creationTime;
|
||||
};
|
||||
|
||||
void AddItemsSetItem(Player* player, Item* item);
|
||||
|
||||
@@ -4948,8 +4948,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
//"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, "
|
||||
// 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
||||
//"health, power1, power2, power3, power4, power5, power6, power7, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, ammoId, knownTitles,
|
||||
// 70 71 72 73
|
||||
//"actionBars, grantableLevels, innTriggerId, extraBonusTalentCount FROM characters WHERE guid = '{}'", guid);
|
||||
// 70 71 72 73 74
|
||||
//"actionBars, grantableLevels, innTriggerId, extraBonusTalentCount, UNIX_TIMESTAMP(creation_date) FROM characters WHERE guid = '{}'", guid);
|
||||
PreparedQueryResult result = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM);
|
||||
|
||||
if (!result)
|
||||
@@ -5026,6 +5026,9 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
SetObjectScale(1.0f);
|
||||
SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f);
|
||||
|
||||
// load character creation date, relevant for achievements of type average
|
||||
SetCreationTime(fields[74].Get<Seconds>());
|
||||
|
||||
// load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria)
|
||||
m_achievementMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS));
|
||||
|
||||
|
||||
@@ -13973,6 +13973,9 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
|
||||
// additional checks - only PvP case
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
{
|
||||
if (!IsPvP() && bySpell && bySpell->IsAffectingArea() && !bySpell->HasAttribute(SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK))
|
||||
return false;
|
||||
|
||||
if (target->IsPvP())
|
||||
return true;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ AC_API_EXPORT EnumText EnumUtils<UnitFlags>::ToString(UnitFlags value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case UNIT_FLAG_NONE: return { "UNIT_FLAG_NONE", "UNIT_FLAG_NONE", "" };
|
||||
case UNIT_FLAG_SERVER_CONTROLLED: return { "UNIT_FLAG_SERVER_CONTROLLED", "UNIT_FLAG_SERVER_CONTROLLED", "set only when unit movement is controlled by server - by SPLINE/MONSTER_MOVE packets, together with UNIT_FLAG_STUNNED; only set to units controlled by client; client function CGUnit_C::IsClientControlled returns false when set for owner" };
|
||||
case UNIT_FLAG_NON_ATTACKABLE: return { "UNIT_FLAG_NON_ATTACKABLE", "UNIT_FLAG_NON_ATTACKABLE", "not attackable" };
|
||||
case UNIT_FLAG_DISABLE_MOVE: return { "UNIT_FLAG_DISABLE_MOVE", "UNIT_FLAG_DISABLE_MOVE", "" };
|
||||
@@ -68,45 +69,46 @@ AC_API_EXPORT EnumText EnumUtils<UnitFlags>::ToString(UnitFlags value)
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<UnitFlags>::Count() { return 32; }
|
||||
AC_API_EXPORT size_t EnumUtils<UnitFlags>::Count() { return 33; }
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT UnitFlags EnumUtils<UnitFlags>::FromIndex(size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return UNIT_FLAG_SERVER_CONTROLLED;
|
||||
case 1: return UNIT_FLAG_NON_ATTACKABLE;
|
||||
case 2: return UNIT_FLAG_DISABLE_MOVE;
|
||||
case 3: return UNIT_FLAG_PLAYER_CONTROLLED;
|
||||
case 4: return UNIT_FLAG_RENAME;
|
||||
case 5: return UNIT_FLAG_PREPARATION;
|
||||
case 6: return UNIT_FLAG_UNK_6;
|
||||
case 7: return UNIT_FLAG_NOT_ATTACKABLE_1;
|
||||
case 8: return UNIT_FLAG_IMMUNE_TO_PC;
|
||||
case 9: return UNIT_FLAG_IMMUNE_TO_NPC;
|
||||
case 10: return UNIT_FLAG_LOOTING;
|
||||
case 11: return UNIT_FLAG_PET_IN_COMBAT;
|
||||
case 12: return UNIT_FLAG_PVP;
|
||||
case 13: return UNIT_FLAG_SILENCED;
|
||||
case 14: return UNIT_FLAG_CANNOT_SWIM;
|
||||
case 15: return UNIT_FLAG_SWIMMING;
|
||||
case 16: return UNIT_FLAG_NON_ATTACKABLE_2;
|
||||
case 17: return UNIT_FLAG_PACIFIED;
|
||||
case 18: return UNIT_FLAG_STUNNED;
|
||||
case 19: return UNIT_FLAG_IN_COMBAT;
|
||||
case 20: return UNIT_FLAG_TAXI_FLIGHT;
|
||||
case 21: return UNIT_FLAG_DISARMED;
|
||||
case 22: return UNIT_FLAG_CONFUSED;
|
||||
case 23: return UNIT_FLAG_FLEEING;
|
||||
case 24: return UNIT_FLAG_POSSESSED;
|
||||
case 25: return UNIT_FLAG_NOT_SELECTABLE;
|
||||
case 26: return UNIT_FLAG_SKINNABLE;
|
||||
case 27: return UNIT_FLAG_MOUNT;
|
||||
case 28: return UNIT_FLAG_UNK_28;
|
||||
case 29: return UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT;
|
||||
case 30: return UNIT_FLAG_SHEATHE;
|
||||
case 31: return UNIT_FLAG_IMMUNE;
|
||||
case 0: return UNIT_FLAG_NONE;
|
||||
case 1: return UNIT_FLAG_SERVER_CONTROLLED;
|
||||
case 2: return UNIT_FLAG_NON_ATTACKABLE;
|
||||
case 3: return UNIT_FLAG_DISABLE_MOVE;
|
||||
case 4: return UNIT_FLAG_PLAYER_CONTROLLED;
|
||||
case 5: return UNIT_FLAG_RENAME;
|
||||
case 6: return UNIT_FLAG_PREPARATION;
|
||||
case 7: return UNIT_FLAG_UNK_6;
|
||||
case 8: return UNIT_FLAG_NOT_ATTACKABLE_1;
|
||||
case 9: return UNIT_FLAG_IMMUNE_TO_PC;
|
||||
case 10: return UNIT_FLAG_IMMUNE_TO_NPC;
|
||||
case 11: return UNIT_FLAG_LOOTING;
|
||||
case 12: return UNIT_FLAG_PET_IN_COMBAT;
|
||||
case 13: return UNIT_FLAG_PVP;
|
||||
case 14: return UNIT_FLAG_SILENCED;
|
||||
case 15: return UNIT_FLAG_CANNOT_SWIM;
|
||||
case 16: return UNIT_FLAG_SWIMMING;
|
||||
case 17: return UNIT_FLAG_NON_ATTACKABLE_2;
|
||||
case 18: return UNIT_FLAG_PACIFIED;
|
||||
case 19: return UNIT_FLAG_STUNNED;
|
||||
case 20: return UNIT_FLAG_IN_COMBAT;
|
||||
case 21: return UNIT_FLAG_TAXI_FLIGHT;
|
||||
case 22: return UNIT_FLAG_DISARMED;
|
||||
case 23: return UNIT_FLAG_CONFUSED;
|
||||
case 24: return UNIT_FLAG_FLEEING;
|
||||
case 25: return UNIT_FLAG_POSSESSED;
|
||||
case 26: return UNIT_FLAG_NOT_SELECTABLE;
|
||||
case 27: return UNIT_FLAG_SKINNABLE;
|
||||
case 28: return UNIT_FLAG_MOUNT;
|
||||
case 29: return UNIT_FLAG_UNK_28;
|
||||
case 30: return UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT;
|
||||
case 31: return UNIT_FLAG_SHEATHE;
|
||||
case 32: return UNIT_FLAG_IMMUNE;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
@@ -116,38 +118,39 @@ AC_API_EXPORT size_t EnumUtils<UnitFlags>::ToIndex(UnitFlags value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case UNIT_FLAG_SERVER_CONTROLLED: return 0;
|
||||
case UNIT_FLAG_NON_ATTACKABLE: return 1;
|
||||
case UNIT_FLAG_DISABLE_MOVE: return 2;
|
||||
case UNIT_FLAG_PLAYER_CONTROLLED: return 3;
|
||||
case UNIT_FLAG_RENAME: return 4;
|
||||
case UNIT_FLAG_PREPARATION: return 5;
|
||||
case UNIT_FLAG_UNK_6: return 6;
|
||||
case UNIT_FLAG_NOT_ATTACKABLE_1: return 7;
|
||||
case UNIT_FLAG_IMMUNE_TO_PC: return 8;
|
||||
case UNIT_FLAG_IMMUNE_TO_NPC: return 9;
|
||||
case UNIT_FLAG_LOOTING: return 10;
|
||||
case UNIT_FLAG_PET_IN_COMBAT: return 11;
|
||||
case UNIT_FLAG_PVP: return 12;
|
||||
case UNIT_FLAG_SILENCED: return 13;
|
||||
case UNIT_FLAG_CANNOT_SWIM: return 14;
|
||||
case UNIT_FLAG_SWIMMING: return 15;
|
||||
case UNIT_FLAG_NON_ATTACKABLE_2: return 16;
|
||||
case UNIT_FLAG_PACIFIED: return 17;
|
||||
case UNIT_FLAG_STUNNED: return 18;
|
||||
case UNIT_FLAG_IN_COMBAT: return 19;
|
||||
case UNIT_FLAG_TAXI_FLIGHT: return 20;
|
||||
case UNIT_FLAG_DISARMED: return 21;
|
||||
case UNIT_FLAG_CONFUSED: return 22;
|
||||
case UNIT_FLAG_FLEEING: return 23;
|
||||
case UNIT_FLAG_POSSESSED: return 24;
|
||||
case UNIT_FLAG_NOT_SELECTABLE: return 25;
|
||||
case UNIT_FLAG_SKINNABLE: return 26;
|
||||
case UNIT_FLAG_MOUNT: return 27;
|
||||
case UNIT_FLAG_UNK_28: return 28;
|
||||
case UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT: return 29;
|
||||
case UNIT_FLAG_SHEATHE: return 30;
|
||||
case UNIT_FLAG_IMMUNE: return 31;
|
||||
case UNIT_FLAG_NONE: return 0;
|
||||
case UNIT_FLAG_SERVER_CONTROLLED: return 1;
|
||||
case UNIT_FLAG_NON_ATTACKABLE: return 2;
|
||||
case UNIT_FLAG_DISABLE_MOVE: return 3;
|
||||
case UNIT_FLAG_PLAYER_CONTROLLED: return 4;
|
||||
case UNIT_FLAG_RENAME: return 5;
|
||||
case UNIT_FLAG_PREPARATION: return 6;
|
||||
case UNIT_FLAG_UNK_6: return 7;
|
||||
case UNIT_FLAG_NOT_ATTACKABLE_1: return 8;
|
||||
case UNIT_FLAG_IMMUNE_TO_PC: return 9;
|
||||
case UNIT_FLAG_IMMUNE_TO_NPC: return 10;
|
||||
case UNIT_FLAG_LOOTING: return 11;
|
||||
case UNIT_FLAG_PET_IN_COMBAT: return 12;
|
||||
case UNIT_FLAG_PVP: return 13;
|
||||
case UNIT_FLAG_SILENCED: return 14;
|
||||
case UNIT_FLAG_CANNOT_SWIM: return 15;
|
||||
case UNIT_FLAG_SWIMMING: return 16;
|
||||
case UNIT_FLAG_NON_ATTACKABLE_2: return 17;
|
||||
case UNIT_FLAG_PACIFIED: return 18;
|
||||
case UNIT_FLAG_STUNNED: return 19;
|
||||
case UNIT_FLAG_IN_COMBAT: return 20;
|
||||
case UNIT_FLAG_TAXI_FLIGHT: return 21;
|
||||
case UNIT_FLAG_DISARMED: return 22;
|
||||
case UNIT_FLAG_CONFUSED: return 23;
|
||||
case UNIT_FLAG_FLEEING: return 24;
|
||||
case UNIT_FLAG_POSSESSED: return 25;
|
||||
case UNIT_FLAG_NOT_SELECTABLE: return 26;
|
||||
case UNIT_FLAG_SKINNABLE: return 27;
|
||||
case UNIT_FLAG_MOUNT: return 28;
|
||||
case UNIT_FLAG_UNK_28: return 29;
|
||||
case UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT: return 30;
|
||||
case UNIT_FLAG_SHEATHE: return 31;
|
||||
case UNIT_FLAG_IMMUNE: return 32;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
@@ -187,12 +190,13 @@ AC_API_EXPORT EnumText EnumUtils<NPCFlags>::ToString(NPCFlags value)
|
||||
case UNIT_NPC_FLAG_SPELLCLICK: return { "UNIT_NPC_FLAG_SPELLCLICK", "has spell click enabled", "cause client to send 1015 opcode (spell click)" };
|
||||
case UNIT_NPC_FLAG_PLAYER_VEHICLE: return { "UNIT_NPC_FLAG_PLAYER_VEHICLE", "is player vehicle", "players with mounts that have vehicle data should have it set" };
|
||||
case UNIT_NPC_FLAG_MAILBOX: return { "UNIT_NPC_FLAG_MAILBOX", "is mailbox", "" };
|
||||
case UNIT_NPC_FLAG_VENDOR_MASK: return { "UNIT_NPC_FLAG_VENDOR_MASK", "UNIT_NPC_FLAG_VENDOR_MASK", "" };
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<NPCFlags>::Count() { return 27; }
|
||||
AC_API_EXPORT size_t EnumUtils<NPCFlags>::Count() { return 28; }
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT NPCFlags EnumUtils<NPCFlags>::FromIndex(size_t index)
|
||||
@@ -226,6 +230,7 @@ AC_API_EXPORT NPCFlags EnumUtils<NPCFlags>::FromIndex(size_t index)
|
||||
case 24: return UNIT_NPC_FLAG_SPELLCLICK;
|
||||
case 25: return UNIT_NPC_FLAG_PLAYER_VEHICLE;
|
||||
case 26: return UNIT_NPC_FLAG_MAILBOX;
|
||||
case 27: return UNIT_NPC_FLAG_VENDOR_MASK;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
@@ -262,6 +267,7 @@ AC_API_EXPORT size_t EnumUtils<NPCFlags>::ToIndex(NPCFlags value)
|
||||
case UNIT_NPC_FLAG_SPELLCLICK: return 24;
|
||||
case UNIT_NPC_FLAG_PLAYER_VEHICLE: return 25;
|
||||
case UNIT_NPC_FLAG_MAILBOX: return 26;
|
||||
case UNIT_NPC_FLAG_VENDOR_MASK: return 27;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2863,47 +2863,43 @@ void ObjectMgr::LoadItemTemplates()
|
||||
|
||||
if (dbcitem)
|
||||
{
|
||||
if (itemTemplate.Class != dbcitem->ClassID)
|
||||
if (enforceDBCAttributes)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({}), must be ({}).", entry, itemTemplate.Class, dbcitem->ClassID);
|
||||
if (enforceDBCAttributes)
|
||||
if (itemTemplate.Class != dbcitem->ClassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({}), must be ({}).", entry, itemTemplate.Class, dbcitem->ClassID);
|
||||
itemTemplate.Class = dbcitem->ClassID;
|
||||
}
|
||||
if (itemTemplate.SubClass != dbcitem->SubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}, must be ({}).", entry, itemTemplate.SubClass, itemTemplate.Class, dbcitem->SubclassID);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.SubClass != dbcitem->SubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}, must be ({}).", entry, itemTemplate.SubClass, itemTemplate.Class, dbcitem->SubclassID);
|
||||
itemTemplate.SubClass = dbcitem->SubclassID;
|
||||
}
|
||||
if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct SoundOverrideSubclass ({}), must be {}.", entry, itemTemplate.SoundOverrideSubclass);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct SoundOverrideSubclass ({}), must be {}.", entry, itemTemplate.SoundOverrideSubclass, dbcitem->SoundOverrideSubclassID);
|
||||
itemTemplate.SoundOverrideSubclass = dbcitem->SoundOverrideSubclassID;
|
||||
}
|
||||
if (itemTemplate.Material != dbcitem->Material)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.Material != dbcitem->Material)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
|
||||
itemTemplate.Material = dbcitem->Material;
|
||||
}
|
||||
if (itemTemplate.InventoryType != dbcitem->InventoryType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({}), must be {}.", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.InventoryType != dbcitem->InventoryType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({}), must be {}.", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
|
||||
itemTemplate.InventoryType = dbcitem->InventoryType;
|
||||
}
|
||||
if (itemTemplate.DisplayInfoID != dbcitem->DisplayInfoID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.DisplayInfoID != dbcitem->DisplayInfoID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
|
||||
itemTemplate.DisplayInfoID = dbcitem->DisplayInfoID;
|
||||
}
|
||||
if (itemTemplate.Sheath != dbcitem->SheatheType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({}), must be {}.", entry, itemTemplate.Sheath, dbcitem->SheatheType);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.Sheath != dbcitem->SheatheType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({}), must be {}.", entry, itemTemplate.Sheath, dbcitem->SheatheType);
|
||||
itemTemplate.Sheath = dbcitem->SheatheType;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -4062,88 +4058,6 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
}
|
||||
}
|
||||
|
||||
// Loading levels data (class only dependent)
|
||||
LOG_INFO("server.loading", "Loading Player Create Level HP/Mana Data...");
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2 3
|
||||
QueryResult result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_FATAL("server.loading", ">> Loaded 0 level health/mana definitions. DB table `player_classlevelstats` is empty.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 current_class = fields[0].Get<uint8>();
|
||||
if (current_class >= MAX_CLASSES)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong class {} in `player_classlevelstats` table, ignoring.", current_class);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8 current_level = fields[1].Get<uint8>(); // Can't be > than STRONG_MAX_LEVEL (hardcoded level maximum) due to var type
|
||||
if (current_level > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
LOG_INFO("sql.sql", "Unused (> MaxPlayerLevel in worldserver.conf) level {} in `player_classlevelstats` table, ignoring.", current_level);
|
||||
++count; // make result loading percent "expected" correct in case disabled detail mode for example.
|
||||
continue;
|
||||
}
|
||||
|
||||
PlayerClassInfo* info = _playerClassInfo[current_class];
|
||||
if (!info)
|
||||
{
|
||||
info = new PlayerClassInfo();
|
||||
info->levelInfo = new PlayerClassLevelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)];
|
||||
_playerClassInfo[current_class] = info;
|
||||
}
|
||||
|
||||
PlayerClassLevelInfo& levelInfo = info->levelInfo[current_level - 1];
|
||||
|
||||
levelInfo.basehealth = fields[2].Get<uint32>();
|
||||
levelInfo.basemana = fields[3].Get<uint32>();
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
// Fill gaps and check integrity
|
||||
for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
|
||||
{
|
||||
// skip non existed classes
|
||||
if (!sChrClassesStore.LookupEntry(class_))
|
||||
continue;
|
||||
|
||||
PlayerClassInfo* pClassInfo = _playerClassInfo[class_];
|
||||
|
||||
// fatal error if no initial level data
|
||||
if (!pClassInfo->levelInfo || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) - 1].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) - 1].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} initial level does not have health/mana data!", class_);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// fill level gaps
|
||||
for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
{
|
||||
if ((pClassInfo->levelInfo[level].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (level >= sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) && pClassInfo->levelInfo[level].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} level {} does not have health/mana data. Using stats data of level {}.", class_, level + 1, level);
|
||||
pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Level Health/Mana Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
// Loading levels data (class/race dependent)
|
||||
LOG_INFO("server.loading", "Loading Player Create Level Stats Data...");
|
||||
{
|
||||
@@ -4182,8 +4096,8 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
|
||||
} while (raceStatsResult->NextRow());
|
||||
|
||||
// 0 1 2 3 4 5 6
|
||||
QueryResult result = WorldDatabase.Query("SELECT Class, Level, Strength, Agility, Stamina, Intellect, Spirit FROM player_class_stats");
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
QueryResult result = WorldDatabase.Query("SELECT Class, Level, Strength, Agility, Stamina, Intellect, Spirit, BaseHP, BaseMana FROM player_class_stats");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -4207,7 +4121,7 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
uint32 current_level = fields[1].Get<uint8>();
|
||||
if (current_level > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
|
||||
if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
|
||||
LOG_ERROR("sql.sql", "Wrong (> {}) level {} in `player_class_stats` table, ignoring.", STRONG_MAX_LEVEL, current_level);
|
||||
else
|
||||
LOG_DEBUG("sql.sql", "Unused (> MaxPlayerLevel in worldserver.conf) level {} in `player_class_stats` table, ignoring.", current_level);
|
||||
@@ -4228,6 +4142,19 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
}
|
||||
}
|
||||
|
||||
PlayerClassInfo* info = _playerClassInfo[current_class];
|
||||
if (!info)
|
||||
{
|
||||
info = new PlayerClassInfo();
|
||||
info->levelInfo = new PlayerClassLevelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)];
|
||||
_playerClassInfo[current_class] = info;
|
||||
}
|
||||
|
||||
PlayerClassLevelInfo& levelInfo = info->levelInfo[current_level - 1];
|
||||
|
||||
levelInfo.basehealth = fields[7].Get<uint32>();
|
||||
levelInfo.basemana = fields[8].Get<uint32>();
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
@@ -4244,6 +4171,7 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
if (!sChrClassesStore.LookupEntry(class_))
|
||||
continue;
|
||||
|
||||
PlayerClassInfo* pClassInfo = _playerClassInfo[class_];
|
||||
PlayerInfo* info = _playerInfo[race][class_];
|
||||
if (!info)
|
||||
continue;
|
||||
@@ -4256,14 +4184,21 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
if (sWorld->getIntConfig(CONFIG_EXPANSION) < EXPANSION_WRATH_OF_THE_LICH_KING && class_ == CLASS_DEATH_KNIGHT)
|
||||
continue;
|
||||
|
||||
// fatal error if no initial level data
|
||||
// fatal error if no initial stats data
|
||||
if (!info->levelInfo || (info->levelInfo[sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) - 1].stats[0] == 0 && class_ != CLASS_DEATH_KNIGHT) || (info->levelInfo[sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) - 1].stats[0] == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Race {} class {} initial level does not have stats data!", race, class_);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// fill level gaps
|
||||
// fatal error if no initial health/mana data
|
||||
if (!pClassInfo->levelInfo || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) - 1].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) - 1].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} initial level does not have health/mana data!", class_);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// fill level gaps for stats
|
||||
for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
{
|
||||
if ((info->levelInfo[level].stats[0] == 0 && class_ != CLASS_DEATH_KNIGHT) || (level >= sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) && info->levelInfo[level].stats[0] == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
@@ -4272,6 +4207,16 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
info->levelInfo[level] = info->levelInfo[level - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// fill level gaps for health/mana
|
||||
for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
{
|
||||
if ((pClassInfo->levelInfo[level].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (level >= sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) && pClassInfo->levelInfo[level].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} level {} does not have health/mana data. Using stats data of level {}.", class_, level + 1, level);
|
||||
pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -536,6 +536,9 @@ void WorldSession::HandleLootRoll(WorldPacket& recvData)
|
||||
case ROLL_GREED:
|
||||
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1);
|
||||
break;
|
||||
case ROLL_DISENCHANT:
|
||||
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -675,6 +675,8 @@ InstancePlayerBind* InstanceSaveMgr::PlayerBindToInstance(ObjectGuid guid, Insta
|
||||
stmt->SetData(1, save->GetInstanceId());
|
||||
stmt->SetData(2, permanent);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID, 1);
|
||||
}
|
||||
|
||||
if (bind.save != save)
|
||||
|
||||
@@ -218,6 +218,11 @@ void InstanceScript::UpdateMinionState(Creature* minion, EncounterState state)
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceScript::Update(uint32 diff)
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
void InstanceScript::UpdateDoorState(GameObject* door)
|
||||
{
|
||||
DoorInfoMapBounds range = doors.equal_range(door->GetEntry());
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "World.h"
|
||||
#include "ZoneScript.h"
|
||||
#include <set>
|
||||
@@ -159,7 +160,7 @@ public:
|
||||
|
||||
void SaveToDB();
|
||||
|
||||
virtual void Update(uint32 /*diff*/) {}
|
||||
virtual void Update(uint32 /*diff*/);
|
||||
|
||||
//Used by the map's CanEnter function.
|
||||
//This is to prevent players from entering during boss encounters.
|
||||
@@ -263,6 +264,8 @@ public:
|
||||
|
||||
// Allows executing code using all creatures registered in the instance script as minions
|
||||
void DoForAllMinions(uint32 id, std::function<void(Creature*)> exec);
|
||||
|
||||
TaskScheduler scheduler;
|
||||
protected:
|
||||
void SetHeaders(std::string const& dataHeaders);
|
||||
void SetBossNumber(uint32 number) { bosses.resize(number); }
|
||||
|
||||
@@ -1058,7 +1058,7 @@ enum AcoreStrings
|
||||
LANG_COMMAND_TICKETLISTRESPONSE = 2029,
|
||||
LANG_COMMAND_TICKETCOMPLETED = 2030,
|
||||
|
||||
// Trinity strings 5000-9999
|
||||
// acore strings 5000-9999
|
||||
LANG_COMMAND_FREEZE = 5000,
|
||||
LANG_COMMAND_FREEZE_ERROR = 5001,
|
||||
LANG_COMMAND_FREEZE_WRONG = 5002,
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVEPLINE_H
|
||||
#define TRINITYSERVER_MOVEPLINE_H
|
||||
#ifndef AC_MOVEPLINE_H
|
||||
#define AC_MOVEPLINE_H
|
||||
|
||||
#include "MoveSplineInitArgs.h"
|
||||
#include "Spline.h"
|
||||
@@ -132,4 +132,4 @@ namespace Movement
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // TRINITYSERVER_MOVEPLINE_H
|
||||
#endif // AC_MOVEPLINE_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#define TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#ifndef AC_MOVESPLINEFLAG_H
|
||||
#define AC_MOVESPLINEFLAG_H
|
||||
|
||||
#include "MovementTypedefs.h"
|
||||
#include <string>
|
||||
@@ -145,4 +145,4 @@ namespace Movement
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#endif // AC_MOVESPLINEFLAG_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEINIT_H
|
||||
#define TRINITYSERVER_MOVESPLINEINIT_H
|
||||
#ifndef AC_MOVESPLINEINIT_H
|
||||
#define AC_MOVESPLINEINIT_H
|
||||
|
||||
#include "MoveSplineInitArgs.h"
|
||||
#include "PathGenerator.h"
|
||||
@@ -209,4 +209,4 @@ namespace Movement
|
||||
|
||||
inline void MoveSplineInit::DisableTransportPathTransformations() { args.TransformForTransport = false; }
|
||||
}
|
||||
#endif // TRINITYSERVER_MOVESPLINEINIT_H
|
||||
#endif // AC_MOVESPLINEINIT_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
#define TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
#ifndef AC_MOVESPLINEINIT_ARGS_H
|
||||
#define AC_MOVESPLINEINIT_ARGS_H
|
||||
|
||||
#include "MoveSplineFlag.h"
|
||||
#include <G3D/Vector3.h>
|
||||
@@ -68,4 +68,4 @@ namespace Movement
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
#endif // AC_MOVESPLINEINIT_ARGS_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_PACKET_BUILDER_H
|
||||
#define TRINITYSERVER_PACKET_BUILDER_H
|
||||
#ifndef AC_PACKET_BUILDER_H
|
||||
#define AC_PACKET_BUILDER_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
@@ -40,4 +40,4 @@ namespace Movement
|
||||
static void WriteCreate(const MoveSpline& mov, ByteBuffer& data);
|
||||
};
|
||||
}
|
||||
#endif // TRINITYSERVER_PACKET_BUILDER_H
|
||||
#endif // AC_PACKET_BUILDER_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_TYPEDEFS_H
|
||||
#define TRINITYSERVER_TYPEDEFS_H
|
||||
#ifndef AC_TYPEDEFS_H
|
||||
#define AC_TYPEDEFS_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
@@ -74,4 +74,4 @@ namespace Movement
|
||||
extern UInt32Counter splineIdGen;
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_TYPEDEFS_H
|
||||
#endif // AC_TYPEDEFS_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_SPLINE_H
|
||||
#define TRINITYSERVER_SPLINE_H
|
||||
#ifndef AC_SPLINE_H
|
||||
#define AC_SPLINE_H
|
||||
|
||||
#include "Errors.h"
|
||||
#include "MovementTypedefs.h"
|
||||
@@ -210,4 +210,4 @@ namespace Movement
|
||||
|
||||
#include "SplineImpl.h"
|
||||
|
||||
#endif // TRINITYSERVER_SPLINE_H
|
||||
#endif // AC_SPLINE_H
|
||||
|
||||
@@ -178,6 +178,21 @@ bool ScriptMgr::OnAllowedForPlayerLootCheck(Player const* player, ObjectGuid sou
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnAllowedToLootContainerCheck(Player const* player, ObjectGuid source)
|
||||
{
|
||||
auto ret = IsValidBoolScript<GlobalScript>([&](GlobalScript* script)
|
||||
{
|
||||
return script->OnAllowedToLootContainerCheck(player, source);
|
||||
});
|
||||
|
||||
if (ret && *ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when an instance Id is deleted, usually because it expired or no players are bound to it anymore.
|
||||
*
|
||||
|
||||
@@ -74,6 +74,21 @@ void ScriptMgr::OnPlayerReleasedGhost(Player* player)
|
||||
});
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell)
|
||||
{
|
||||
auto ret = IsValidBoolScript<PlayerScript>([player, mapId, zoneId, bySpell](PlayerScript* script)
|
||||
{
|
||||
return !script->OnCanPlayerFlyInZone(player, mapId, zoneId, bySpell);
|
||||
});
|
||||
|
||||
if (ret && *ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPVPKill(Player* killer, Player* killed)
|
||||
{
|
||||
ExecuteScript<PlayerScript>([&](PlayerScript* script)
|
||||
|
||||
@@ -1474,6 +1474,16 @@ public:
|
||||
*/
|
||||
virtual void OnQuestAbandon(Player* /*player*/, uint32 /*questId*/) { }
|
||||
|
||||
/**
|
||||
* @brief This hook called before other CanFlyChecks are applied
|
||||
*
|
||||
* @param player Contains information about the Player
|
||||
* @param mapId Contains information about the current map id
|
||||
* @param zoneId Contains information about the current zone
|
||||
* @param bySpell Contains information about the spell that invoked the check
|
||||
*/
|
||||
[[nodiscard]] virtual bool OnCanPlayerFlyInZone(Player* /*player*/, uint32 /*mapId*/, uint32 /*zoneId*/, SpellInfo const* /*bySpell*/) { return true; }
|
||||
|
||||
// Passive Anticheat System
|
||||
virtual void AnticheatSetSkipOnePacketForASH(Player* /*player*/, bool /*apply*/) { }
|
||||
virtual void AnticheatSetCanFlybyServer(Player* /*player*/, bool /*apply*/) { }
|
||||
@@ -1648,9 +1658,12 @@ public:
|
||||
// Called after loading spell dbc corrections
|
||||
virtual void OnLoadSpellCustomAttr(SpellInfo* /*spell*/) { }
|
||||
|
||||
// Called when checking if a player can see the creature loot
|
||||
// Called when checking if a player can see the creature loot item
|
||||
virtual bool OnAllowedForPlayerLootCheck(Player const* /*player*/, ObjectGuid /*source*/) { return false; };
|
||||
|
||||
// Called when checking if a player can see the creature loot (if it can click the corpse f.e)
|
||||
virtual bool OnAllowedToLootContainerCheck(Player const* /*player*/, ObjectGuid /*source*/) { return false; };
|
||||
|
||||
// Called when instance id is removed from database (e.g. instance reset)
|
||||
virtual void OnInstanceIdRemoved(uint32 /*instanceId*/) { }
|
||||
|
||||
@@ -2474,6 +2487,7 @@ public: /* PlayerScript */
|
||||
bool CanSendErrorAlreadyLooted(Player* player);
|
||||
void OnAfterCreatureLoot(Player* player);
|
||||
void OnAfterCreatureLootMoney(Player* player);
|
||||
bool OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell);
|
||||
|
||||
// Anti cheat
|
||||
void AnticheatSetSkipOnePacketForASH(Player* player, bool apply);
|
||||
@@ -2535,6 +2549,7 @@ public: /* GlobalScript */
|
||||
bool OnSpellHealingBonusTakenNegativeModifiers(Unit const* target, Unit const* caster, SpellInfo const* spellInfo, float& val);
|
||||
void OnLoadSpellCustomAttr(SpellInfo* spell);
|
||||
bool OnAllowedForPlayerLootCheck(Player const* player, ObjectGuid source);
|
||||
bool OnAllowedToLootContainerCheck(Player const* player, ObjectGuid source);
|
||||
void OnInstanceIdRemoved(uint32 instanceId);
|
||||
void OnBeforeSetBossState(uint32 id, EncounterState newState, EncounterState oldState, Map* instance);
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace WorldPackets
|
||||
class AC_GAME_API PlayMusic final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress missingReturn
|
||||
PlayMusic() : ServerPacket(SMSG_PLAY_MUSIC, 4) { }
|
||||
PlayMusic(uint32 soundKitID) : ServerPacket(SMSG_PLAY_MUSIC, 4), SoundKitID(soundKitID) { }
|
||||
|
||||
@@ -68,6 +69,7 @@ namespace WorldPackets
|
||||
class AC_GAME_API PlayObjectSound final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress missingReturn
|
||||
PlayObjectSound() : ServerPacket(SMSG_PLAY_OBJECT_SOUND, 4 + 8) { }
|
||||
PlayObjectSound(ObjectGuid const& sourceObjectGUID, uint32 soundKitID)
|
||||
: ServerPacket(SMSG_PLAY_OBJECT_SOUND, 4 + 8), SourceObjectGUID(sourceObjectGUID), SoundKitID(soundKitID) { }
|
||||
@@ -82,6 +84,7 @@ namespace WorldPackets
|
||||
class AC_GAME_API Playsound final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress missingReturn
|
||||
Playsound() : ServerPacket(SMSG_PLAY_SOUND, 4) { }
|
||||
Playsound(uint32 soundKitID) : ServerPacket(SMSG_PLAY_SOUND, 4), SoundKitID(soundKitID) { }
|
||||
|
||||
|
||||
@@ -564,7 +564,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes
|
||||
//! Negative mutetime indicates amount of minutes to be muted effective on next login - which is now.
|
||||
if (account.MuteTime < 0)
|
||||
{
|
||||
account.MuteTime = GameTime::GetGameTime().count() + llabs(account.MuteTime);
|
||||
account.MuteTime = GameTime::GetGameTime().count() + std::llabs(account.MuteTime);
|
||||
|
||||
auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
|
||||
stmt->SetData(0, account.MuteTime);
|
||||
|
||||
@@ -6088,23 +6088,6 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
// for effects of spells that have only one target
|
||||
switch (m_spellInfo->Effects[i].Effect)
|
||||
{
|
||||
case SPELL_EFFECT_DUMMY:
|
||||
{
|
||||
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT)
|
||||
{
|
||||
// Raise Ally
|
||||
if( m_spellInfo->Id == 61999 )
|
||||
{
|
||||
Unit* target = m_targets.GetUnitTarget();
|
||||
if (!target)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (target->IsAlive()) // not discovered attributeEx5?
|
||||
return SPELL_FAILED_TARGET_NOT_DEAD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPELL_EFFECT_LEARN_SPELL:
|
||||
{
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
|
||||
@@ -1470,7 +1470,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player /*= nullptr*/, bool strict /*= true*/) const
|
||||
SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player* player /*= nullptr*/, bool strict /*= true*/) const
|
||||
{
|
||||
// normal case
|
||||
if (AreaGroupId > 0)
|
||||
|
||||
@@ -474,7 +474,7 @@ public:
|
||||
bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
|
||||
|
||||
SpellCastResult CheckShapeshift(uint32 form) const;
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = nullptr, bool strict = true) const;
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player* player = nullptr, bool strict = true) const;
|
||||
SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
|
||||
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
|
||||
bool CheckTargetCreatureType(Unit const* target) const;
|
||||
|
||||
@@ -1530,8 +1530,8 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->ChannelInterruptFlags |= AURA_INTERRUPT_FLAG_MOVE;
|
||||
});
|
||||
|
||||
// Debris
|
||||
ApplySpellFix({ 36449 }, [](SpellInfo* spellInfo)
|
||||
// Debris - Debris Visual
|
||||
ApplySpellFix({ 36449, 30632 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Attributes |= SPELL_ATTR0_AURA_IS_DEBUFF;
|
||||
});
|
||||
@@ -1542,12 +1542,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
|
||||
});
|
||||
|
||||
// Debris Visual
|
||||
ApplySpellFix({ 30632 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_DEST_DYNOBJ_ALLY);
|
||||
});
|
||||
|
||||
// Activate Sunblade Protecto
|
||||
ApplySpellFix({ 46475, 46476 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user