feat(Scripts/Commands): Allow quest status to be used for offline players (#25816)

Co-authored-by: FlyingArowana <TheSCREWEDSoftware@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Skjalf <47818697+Nyeriah@users.noreply.github.com>
This commit is contained in:
Ryan Turner
2026-07-22 11:45:16 +01:00
committed by GitHub
parent 6fc8ef599d
commit 3e741cc44f
3 changed files with 56 additions and 27 deletions

View File

@@ -523,6 +523,9 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, "UPDATE character_queststatus_rewarded SET quest = ? WHERE quest = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE, "UPDATE character_queststatus_rewarded SET active = 1 WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, "UPDATE character_queststatus_rewarded SET active = 0 WHERE quest = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHAR_QUESTSTATUS_BY_QUEST, "SELECT status FROM character_queststatus WHERE guid = ? AND quest = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_QUESTSTATUS_SEASONAL_BY_QUEST, "SELECT 1 FROM character_queststatus_seasonal WHERE guid = ? AND quest = ? AND event = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, "SELECT 1 FROM character_queststatus_rewarded WHERE guid = ? AND quest = ? AND active = 1", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_SKILLS, "INSERT INTO character_skills (guid, skill, value, max) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UDP_CHAR_SKILLS, "UPDATE character_skills SET value = ?, max = ? WHERE guid = ? AND skill = ?", CONNECTION_ASYNC);

View File

@@ -446,6 +446,9 @@ enum CharacterDatabaseStatements : uint32
CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE,
CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE,
CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST,
CHAR_SEL_CHAR_QUESTSTATUS_BY_QUEST,
CHAR_SEL_CHAR_QUESTSTATUS_SEASONAL_BY_QUEST,
CHAR_SEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST,
CHAR_DEL_CHAR_SKILL_BY_SKILL,
CHAR_INS_CHAR_SKILLS,
CHAR_UDP_CHAR_SKILLS,

View File

@@ -729,6 +729,25 @@ public:
return true;
}
static char const* QuestStatusToString(QuestStatus status)
{
switch (status)
{
case QUEST_STATUS_NONE:
return "Not Taken";
case QUEST_STATUS_COMPLETE:
return "Complete";
case QUEST_STATUS_INCOMPLETE:
return "Incomplete";
case QUEST_STATUS_FAILED:
return "Failed";
case QUEST_STATUS_REWARDED:
return "Rewarded";
default:
return "Unknown";
}
}
static bool HandleQuestStatus(ChatHandler* handler, Quest const* quest, Optional<PlayerIdentifier> playerTarget)
{
if (!playerTarget)
@@ -741,33 +760,10 @@ public:
}
uint32 entry = quest->GetQuestId();
std::string status;
if (Player* player = playerTarget->GetConnectedPlayer())
{
QuestStatus qs = player->GetQuestStatus(entry);
switch (qs)
{
case QUEST_STATUS_NONE:
status = "Not Taken";
break;
case QUEST_STATUS_COMPLETE:
status = "Complete";
break;
case QUEST_STATUS_INCOMPLETE:
status = "Incomplete";
break;
case QUEST_STATUS_FAILED:
status = "Failed";
break;
case QUEST_STATUS_REWARDED:
status = "Rewarded";
break;
default:
status = "Unknown";
break;
}
handler->PSendSysMessage(LANG_CMD_QUEST_STATUS, quest->GetTitle(), entry, status);
handler->PSendSysMessage(LANG_CMD_QUEST_STATUS, quest->GetTitle(), entry, QuestStatusToString(player->GetQuestStatus(entry)));
if (!player->CanTakeQuest(quest, false))
{
@@ -846,8 +842,35 @@ public:
}
else
{
handler->SendErrorMessage(LANG_PLAYER_NOT_FOUND);
return false;
ObjectGuid::LowType guid = playerTarget->GetGUID().GetCounter();
char const* status;
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_QUESTSTATUS_BY_QUEST);
stmt->SetData(0, guid);
stmt->SetData(1, entry);
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
status = QuestStatusToString(QuestStatus(result->Fetch()[0].Get<uint8>()));
else if (quest->IsSeasonal())
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_QUESTSTATUS_SEASONAL_BY_QUEST);
stmt->SetData(0, guid);
stmt->SetData(1, entry);
stmt->SetData(2, quest->GetEventIdForQuest());
status = CharacterDatabase.Query(stmt) ? "Rewarded" : "Not Taken";
}
// rewarded repeatable quests report Not Taken, matching Player::GetQuestStatus
else if (!quest->IsRepeatable())
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST);
stmt->SetData(0, guid);
stmt->SetData(1, entry);
status = CharacterDatabase.Query(stmt) ? "Rewarded" : "Not Taken";
}
else
status = "Not Taken";
handler->PSendSysMessage(LANG_CMD_QUEST_STATUS, quest->GetTitle(), entry, status);
}
return true;