Core/SAI: Implemented new action SMART_ACTION_COMPLETE_QUEST (#30048)

This commit is contained in:
Meji
2024-08-15 15:43:17 +02:00
committed by GitHub
parent 585cbd9394
commit 3429871a07
5 changed files with 63 additions and 69 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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:

View File

@@ -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

View File

@@ -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);
}
}