diff --git a/data/sql/updates/pending_db_world/rev_1671958871864691141.sql b/data/sql/updates/pending_db_world/rev_1671958871864691141.sql new file mode 100644 index 000000000..04b73a857 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1671958871864691141.sql @@ -0,0 +1,5 @@ +-- +UPDATE `smart_scripts` SET `action_type`=134 WHERE `action_type` = 85; +DELETE FROM `smart_scripts` WHERE `entryorguid`=25418 AND `source_type`=0 AND `id`=4 AND `link`=5; +DELETE FROM `smart_scripts` WHERE `entryorguid`=25416 AND `source_type`=0 AND `id`=4 AND `link`=5; +DELETE FROM `smart_scripts` WHERE `entryorguid`=33518 AND `source_type`=0 AND `id`=3 AND `link`=0; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index eaed5823a..20e0bb47a 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -597,15 +597,15 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (caster && caster != me) // Areatrigger cast { - caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED)); } - else if (me && (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))) + else if (me && (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))) { - if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) + if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS) me->InterruptNonMeleeSpells(false); // Xinef: flag usable only if caster has max dist set - if ((e.action.cast.flags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0) + if ((e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0) { // Xinef: check mana case only and operate movement accordingly, LoS and range is checked in targetet movement generator SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell); @@ -623,12 +623,45 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } } - me->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + me->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED)); } } break; } + case SMART_ACTION_SELF_CAST: + { + if (targets.empty()) + break; + + if (e.action.cast.targetsLimit) + Acore::Containers::RandomResize(targets, e.action.cast.targetsLimit); + + 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; + } + + for (WorldObject* target : targets) + { + Unit* uTarget = target->ToUnit(); + if (!uTarget) + continue; + + if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !uTarget->HasAura(e.action.cast.spell)) + { + if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS) + uTarget->InterruptNonMeleeSpells(false); + + uTarget->CastSpell(uTarget, e.action.cast.spell, triggerFlags); + } + } + break; + } case SMART_ACTION_INVOKER_CAST: { Unit* tempLastInvoker = GetLastInvoker(unit); // xinef: can be used for area triggers cast @@ -638,7 +671,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (targets.empty()) break; - if (e.action.cast.targetsLimit > 0 && targets.size() > e.action.cast.targetsLimit) + if (e.action.cast.targetsLimit) Acore::Containers::RandomResize(targets, e.action.cast.targetsLimit); for (WorldObject* target : targets) @@ -646,12 +679,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (!IsUnit(target)) continue; - if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)) + if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)) { - if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) + if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS) tempLastInvoker->InterruptNonMeleeSpells(false); - tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED)); + tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED)); } } @@ -4143,7 +4176,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) // delay spell cast event if another spell is being casted if (e.GetActionType() == SMART_ACTION_CAST) { - if (!(e.action.cast.flags & (SMARTCAST_INTERRUPT_PREVIOUS | SMARTCAST_TRIGGERED))) + if (!(e.action.cast.castFlags & (SMARTCAST_INTERRUPT_PREVIOUS | SMARTCAST_TRIGGERED))) { if (me && me->HasUnitState(UNIT_STATE_CASTING)) { @@ -4402,7 +4435,7 @@ void SmartScript::OnInitialize(WorldObject* obj, AreaTrigger const* at) } // Xinef: if smartcast combat move flag is present - if (i->GetActionType() == SMART_ACTION_CAST && (i->action.cast.flags & SMARTCAST_COMBAT_MOVE)) + if (i->GetActionType() == SMART_ACTION_CAST && (i->action.cast.castFlags & SMARTCAST_COMBAT_MOVE)) { if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i->action.cast.spell)) { diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index d4d9efa10..26d52bb23 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -409,7 +409,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e) case SMART_TARGET_INVOKER_PARTY: if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type)) { - LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker target, but action does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker target, but event does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); return false; } break; @@ -620,7 +620,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_THREAT_SINGLE_PCT: return sizeof(SmartAction::threatPCT); case SMART_ACTION_THREAT_ALL_PCT: return sizeof(SmartAction::threatPCT); case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: return sizeof(SmartAction::quest); - //case SMART_ACTION_RESERVED_16: return sizeof(SmartAction::raw); + case SMART_ACTION_RESERVED_16: return sizeof(SmartAction::raw); case SMART_ACTION_SET_EMOTE_STATE: return sizeof(SmartAction::emote); case SMART_ACTION_SET_UNIT_FLAG: return sizeof(SmartAction::unitFlag); case SMART_ACTION_REMOVE_UNIT_FLAG: return sizeof(SmartAction::unitFlag); @@ -690,6 +690,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_ADD_NPC_FLAG: return sizeof(SmartAction::flag); case SMART_ACTION_REMOVE_NPC_FLAG: return sizeof(SmartAction::flag); case SMART_ACTION_SIMPLE_TALK: return sizeof(SmartAction::simpleTalk); + case SMART_ACTION_SELF_CAST: return sizeof(SmartAction::cast); case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast); case SMART_ACTION_CROSS_CAST: return sizeof(SmartAction::crossCast); case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: return sizeof(SmartAction::randTimedActionList); @@ -733,22 +734,21 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e) case SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT: return sizeof(SmartAction::randomTimedEvent); case SMART_ACTION_REMOVE_ALL_GAMEOBJECTS: return NO_PARAMS; // case SMART_ACTION_PAUSE_MOVEMENT: return sizeof(SmartAction::pauseMovement); - //case SMART_ACTION_PLAY_ANIMKIT: return sizeof(SmartAction::raw); - //case SMART_ACTION_SCENE_PLAY: return sizeof(SmartAction::raw); - //case SMART_ACTION_SCENE_CANCEL: return sizeof(SmartAction::raw); + case SMART_ACTION_PLAY_ANIMKIT: return sizeof(SmartAction::raw); + case SMART_ACTION_SCENE_PLAY: return sizeof(SmartAction::raw); + case SMART_ACTION_SCENE_CANCEL: return sizeof(SmartAction::raw); // case SMART_ACTION_SPAWN_SPAWNGROUP: return sizeof(SmartAction::groupSpawn); // case SMART_ACTION_DESPAWN_SPAWNGROUP: return sizeof(SmartAction::groupSpawn); // case SMART_ACTION_RESPAWN_BY_SPAWNID: return sizeof(SmartAction::respawnData); - // case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast); case SMART_ACTION_PLAY_CINEMATIC: return sizeof(SmartAction::cinematic); case SMART_ACTION_SET_MOVEMENT_SPEED: return sizeof(SmartAction::movementSpeed); - //case SMART_ACTION_PLAY_SPELL_VISUAL_KIT: return sizeof(SmartAction::raw); + // case SMART_ACTION_PLAY_SPELL_VISUAL_KIT: return sizeof(SmartAction::raw); // case SMART_ACTION_OVERRIDE_LIGHT: return sizeof(SmartAction::overrideLight); // case SMART_ACTION_OVERRIDE_WEATHER: return sizeof(SmartAction::overrideWeather); - //case SMART_ACTION_SET_AI_ANIM_KIT: return sizeof(SmartAction::raw); + // case SMART_ACTION_SET_AI_ANIM_KIT: return sizeof(SmartAction::raw); case SMART_ACTION_SET_HOVER: return sizeof(SmartAction::setHover); case SMART_ACTION_SET_HEALTH_PCT: return sizeof(SmartAction::setHealthPct); - //case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::raw); + // case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::raw); case SMART_ACTION_MOVE_TO_POS_TARGET: return sizeof(SmartAction::moveToPos); case SMART_ACTION_EXIT_VEHICLE: return NO_PARAMS; case SMART_ACTION_SET_UNIT_MOVEMENT_FLAGS: return sizeof(SmartAction::movementFlag); @@ -1438,11 +1438,14 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) } break; } - case SMART_ACTION_CAST: case SMART_ACTION_INVOKER_CAST: - if (!IsSpellValid(e, e.action.cast.spell)) + if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type)) + { + LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker cast action, but event does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); return false; + } break; + case SMART_ACTION_CAST: case SMART_ACTION_CROSS_CAST: if (!IsSpellValid(e, e.action.crossCast.spell)) return false; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 40583daa5..55477d9a1 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -607,7 +607,7 @@ enum SMART_ACTION SMART_ACTION_ADD_NPC_FLAG = 82, // Flags SMART_ACTION_REMOVE_NPC_FLAG = 83, // Flags SMART_ACTION_SIMPLE_TALK = 84, // groupID, can be used to make players say groupID, Text_over event is not triggered, whisper can not be used (Target units will say the text) - SMART_ACTION_INVOKER_CAST = 85, // spellID, castFlags, if avaliable, last used invoker will cast spellId with castFlags on targets + SMART_ACTION_SELF_CAST = 85, // spellID, castFlags SMART_ACTION_CROSS_CAST = 86, // spellID, castFlags, CasterTargetType, CasterTarget param1, CasterTarget param2, CasterTarget param3, ( + the origonal target fields as Destination target), CasterTargets will cast spellID on all Targets (use with caution if targeting multiple * multiple units) SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST = 87, // script9 ids 1-9 SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST = 88, // script9 id min, max @@ -656,8 +656,8 @@ enum SMART_ACTION SMART_ACTION_SPAWN_SPAWNGROUP = 131, /// @todo: NOT SUPPORTED YET SMART_ACTION_DESPAWN_SPAWNGROUP = 132, /// @todo: NOT SUPPORTED YET SMART_ACTION_RESPAWN_BY_SPAWNID = 133, /// @todo: NOT SUPPORTED YET - // SMART_ACTION_INVOKER_CAST = 134, /// @todo: solve name conflicts - SMART_ACTION_PLAY_CINEMATIC = 135, // entry + SMART_ACTION_INVOKER_CAST = 134, // spellID, castFlags + SMART_ACTION_PLAY_CINEMATIC = 135, // entry, cinematic SMART_ACTION_SET_MOVEMENT_SPEED = 136, // movementType, speedInteger, speedFraction SMART_ACTION_SET_HEALTH_PCT = 142, // percent @@ -801,7 +801,8 @@ struct SmartAction struct { uint32 spell; - uint32 flags; + uint32 castFlags; + uint32 triggerFlags; uint32 targetsLimit; } cast;