Merge branch 'master' of github.com:azerothcore/azerothcore-wotlk into Playerbot

This commit is contained in:
Yunfan Li
2023-09-23 22:44:15 +08:00
154 changed files with 7913 additions and 4858 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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))
+92 -73
View File
@@ -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;
}
+2 -2
View File
@@ -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;
+16 -1
View File
@@ -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))
+6 -1
View File
@@ -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));
+3
View File
@@ -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;
+72 -66
View File
@@ -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");
}
}
+65 -120
View File
@@ -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());
+4 -1
View File
@@ -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); }
+1 -1
View File
@@ -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,
+3 -3
View File
@@ -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
+3 -3
View File
@@ -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)
+16 -1
View File
@@ -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) { }
+1 -1
View File
@@ -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);
-17
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
{