aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeji <alvaro.megias@outlook.com>2024-08-15 15:43:17 +0200
committerGitHub <noreply@github.com>2024-08-15 15:43:17 +0200
commit3429871a07c1c1ebe2bd94cb771ef187cb46fd46 (patch)
tree86525da8a409240074c81d8e5b97100cbb0bd5ca
parent585cbd939442827bd4f1120cc7de1d62d03b7565 (diff)
Core/SAI: Implemented new action SMART_ACTION_COMPLETE_QUEST (#30048)11.0.0.56008
-rw-r--r--sql/updates/world/master/2024_08_15_00_world.sql2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp70
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp37
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h7
-rw-r--r--src/server/game/Spells/SpellEffects.cpp16
5 files changed, 63 insertions, 69 deletions
diff --git a/sql/updates/world/master/2024_08_15_00_world.sql b/sql/updates/world/master/2024_08_15_00_world.sql
new file mode 100644
index 00000000000..857e221c76a
--- /dev/null
+++ b/sql/updates/world/master/2024_08_15_00_world.sql
@@ -0,0 +1,2 @@
+UPDATE `smart_scripts` SET `action_type`=152, `target_type`=16 WHERE `action_type`=26 AND `target_type`=7;
+UPDATE `smart_scripts` SET `action_type`=152 WHERE `action_type`=15;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index ad0e71c2c83..f1294299752 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -575,27 +575,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
break;
}
- case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS:
- {
- for (WorldObject* target : targets)
- {
- // Special handling for vehicles
- if (IsUnit(target))
- if (Vehicle* vehicle = target->ToUnit()->GetVehicleKit())
- for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
- if (Player* player = ObjectAccessor::GetPlayer(*target, seat.second.Passenger.Guid))
- player->AreaExploredOrEventHappens(e.action.quest.quest);
-
- if (IsPlayer(target))
- {
- target->ToPlayer()->AreaExploredOrEventHappens(e.action.quest.quest);
-
- TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player {} credited quest {}",
- target->GetGUID().ToString(), e.action.quest.quest);
- }
- }
- break;
- }
case SMART_ACTION_CAST:
{
if (targets.empty())
@@ -869,27 +848,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature {} DoFleeToGetAssistance", me->GetGUID().ToString());
break;
}
- case SMART_ACTION_CALL_GROUPEVENTHAPPENS:
- {
- if (!unit)
- break;
-
- // If invoker was pet or charm
- Player* playerCharmed = unit->GetCharmerOrOwnerPlayerOrPlayerItself();
- if (playerCharmed && GetBaseObject())
- {
- playerCharmed->GroupEventHappens(e.action.quest.quest, GetBaseObject());
- TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {}, group credit for quest {}",
- unit->GetGUID().ToString(), e.action.quest.quest);
- }
-
- // Special handling for vehicles
- if (Vehicle* vehicle = unit->GetVehicleKit())
- for (std::pair<int8 const, VehicleSeat>& seat : vehicle->Seats)
- if (Player* passenger = ObjectAccessor::GetPlayer(*unit, seat.second.Passenger.Guid))
- passenger->GroupEventHappens(e.action.quest.quest, GetBaseObject());
- break;
- }
case SMART_ACTION_COMBAT_STOP:
{
if (!me)
@@ -2637,6 +2595,34 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
}
+ case SMART_ACTION_COMPLETE_QUEST:
+ {
+ uint32 questId = e.action.quest.quest;
+ Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
+ if (!quest)
+ break;
+
+ for (WorldObject* target : targets)
+ {
+ Player* player = Object::ToPlayer(target);
+ if (!player)
+ continue;
+
+ QuestStatus questStatus = player->GetQuestStatus(questId);
+ if (questStatus == QUEST_STATUS_REWARDED)
+ continue;
+
+ if (quest->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) || quest->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER))
+ {
+ if (questStatus == QUEST_STATUS_INCOMPLETE)
+ player->AreaExploredOrEventHappens(questId);
+ }
+ else if (quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT)) // Check if the quest is used as a serverside flag
+ player->CompleteQuest(questId);
+ }
+
+ break;
+ }
default:
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index c9e1cb072fe..49b61246894 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -340,7 +340,6 @@ void SmartAIMgr::LoadSmartAIFromDB()
}
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) && temp.source_type != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST)
{
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
@@ -910,7 +909,6 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_SUMMON_CREATURE: return sizeof(SmartAction::summonCreature);
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_SET_INGAME_PHASE_GROUP: return sizeof(SmartAction::ingamePhaseGroup);
case SMART_ACTION_SET_EMOTE_STATE: return sizeof(SmartAction::emote);
case SMART_ACTION_AUTO_ATTACK: return sizeof(SmartAction::autoAttack);
@@ -919,7 +917,6 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_INC_EVENT_PHASE: return sizeof(SmartAction::incEventPhase);
case SMART_ACTION_EVADE: return sizeof(SmartAction::evade);
case SMART_ACTION_FLEE_FOR_ASSIST: return sizeof(SmartAction::fleeAssist);
- case SMART_ACTION_CALL_GROUPEVENTHAPPENS: return sizeof(SmartAction::quest);
case SMART_ACTION_COMBAT_STOP: return NO_PARAMS;
case SMART_ACTION_REMOVEAURASFROMSPELL: return sizeof(SmartAction::removeAura);
case SMART_ACTION_FOLLOW: return sizeof(SmartAction::follow);
@@ -1028,6 +1025,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER: return sizeof(SmartAction::becomePersonalClone);
case SMART_ACTION_TRIGGER_GAME_EVENT: return sizeof(SmartAction::triggerGameEvent);
case SMART_ACTION_DO_ACTION: return sizeof(SmartAction::doAction);
+ case SMART_ACTION_COMPLETE_QUEST: return sizeof(SmartAction::quest);
default:
TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -1792,22 +1790,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
break;
- case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS:
- case SMART_ACTION_CALL_GROUPEVENTHAPPENS:
- if (Quest const* qid = sObjectMgr->GetQuestTemplate(e.action.quest.quest))
- {
- if (!qid->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) && !qid->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER))
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Flags for Quest entry {} does not include QUEST_FLAGS_COMPLETION_EVENT or QUEST_FLAGS_COMPLETION_AREA_TRIGGER, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
- return false;
- }
- }
- else
- {
- TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Quest entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
- return false;
- }
- break;
case SMART_ACTION_SET_EVENT_PHASE:
if (e.action.setEventPhase.phase >= SMART_EVENT_PHASE_MAX)
{
@@ -2465,7 +2447,24 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
TC_SAI_IS_BOOLEAN_VALID(e, e.action.triggerGameEvent.useSaiTargetAsGameEventSource);
break;
}
+ case SMART_ACTION_COMPLETE_QUEST:
+ if (Quest const* quest = sObjectMgr->GetQuestTemplate(e.action.quest.quest))
+ {
+ if (!quest->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) && !quest->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER) && !quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Flags for Quest entry {} does not include QUEST_FLAGS_COMPLETION_EVENT or QUEST_FLAGS_COMPLETION_AREA_TRIGGER or QUEST_FLAGS_TRACKING_EVENT, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
+ return false;
+ }
+ }
+ else
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Quest entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
+ return false;
+ }
+ break;
// Unused
+ case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS:
+ case SMART_ACTION_CALL_GROUPEVENTHAPPENS:
case SMART_ACTION_SET_UNIT_FLAG:
case SMART_ACTION_REMOVE_UNIT_FLAG:
case SMART_ACTION_INSTALL_AI_TEMPLATE:
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 50b8ade0fef..23c449ab34e 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -472,7 +472,7 @@ enum SMART_ACTION
SMART_ACTION_SUMMON_CREATURE = 12, // CreatureID, summonType, duration in ms, attackInvoker, flags(SmartActionSummonCreatureFlags)
SMART_ACTION_THREAT_SINGLE_PCT = 13, // Threat%
SMART_ACTION_THREAT_ALL_PCT = 14, // Threat%
- SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS = 15, // QuestID
+ SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS = 15, // UNUSED, DO NOT REUSE
SMART_ACTION_SET_INGAME_PHASE_GROUP = 16, // phaseGroupId, apply
SMART_ACTION_SET_EMOTE_STATE = 17, // emoteID
SMART_ACTION_SET_UNIT_FLAG = 18, // UNUSED, DO NOT REUSE
@@ -483,7 +483,7 @@ enum SMART_ACTION
SMART_ACTION_INC_EVENT_PHASE = 23, // Value (may be negative to decrement phase, should not be 0)
SMART_ACTION_EVADE = 24, // toRespawnPosition (0 = Move to RespawnPosition, 1 = Move to last stored home position)
SMART_ACTION_FLEE_FOR_ASSIST = 25, // With Emote
- SMART_ACTION_CALL_GROUPEVENTHAPPENS = 26, // QuestID
+ SMART_ACTION_CALL_GROUPEVENTHAPPENS = 26, // UNUSED, DO NOT REUSE
SMART_ACTION_COMBAT_STOP = 27, //
SMART_ACTION_REMOVEAURASFROMSPELL = 28, // Spellid (0 removes all auras), charges (0 removes aura)
SMART_ACTION_FOLLOW = 29, // Distance (0 = default), Angle (0 = default), EndCreatureEntry, credit, creditType (0monsterkill, 1event)
@@ -609,7 +609,8 @@ enum SMART_ACTION
SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER = 149, // summonType 1-8, duration in ms
SMART_ACTION_TRIGGER_GAME_EVENT = 150, // eventId, useSaiTargetAsGameEventSource
SMART_ACTION_DO_ACTION = 151, // actionId
- SMART_ACTION_END = 152
+ SMART_ACTION_COMPLETE_QUEST = 152, // QuestId. Regular quests with objectives can't be completed with this action (only quests with QUEST_FLAGS_COMPLETION_EVENT, QUEST_FLAGS_COMPLETION_AREA_TRIGGER or QUEST_FLAGS_TRACKING_EVENT)
+ SMART_ACTION_END = 153
};
enum class SmartActionSummonCreatureFlags
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 54d36d7f24e..c74646f42c0 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -3690,11 +3690,17 @@ void Spell::EffectQuestComplete()
if (!quest)
return;
- uint16 logSlot = player->FindQuestSlot(questId);
- if (logSlot < MAX_QUEST_LOG_SIZE)
- player->AreaExploredOrEventHappens(questId);
- else if (quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT)) // Check if the quest is used as a serverside flag.
- player->SetRewardedQuest(questId); // If so, set status to rewarded without broadcasting it to client.
+ QuestStatus questStatus = player->GetQuestStatus(questId);
+ if (questStatus == QUEST_STATUS_REWARDED)
+ return;
+
+ if (quest->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) || quest->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER))
+ {
+ if (questStatus == QUEST_STATUS_INCOMPLETE)
+ player->AreaExploredOrEventHappens(questId);
+ }
+ else if (quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT)) // Check if the quest is used as a serverside flag
+ player->CompleteQuest(questId);
}
}