Code:
__int64 __usercall Script_IsQuestComplete@<rax>(__int64 a1@<rcx>, float a2@<xmm0>)
{
__int64 v2; // r14
__int64 result; // rax
int questID; // eax
int completed; // esi
unsigned int questEntryIndexInQuestLog; // edi
unsigned int pQuestID; // ebx
int *questLogEntryPtr; // rcx
__int64 activePlayerPtr; // rax
__int64 startOfQuestLogEntry; // rbx
__int64 m_activePlayerPtr; // rax
__int64 questIndex; // rcx
__int64 questInfoPtr; // rbp
int *questIdFromLogEntry; // rbx
__int64 questGiverId; // rax
__int64 questCacheEntryResult; // rax
__int64 questCacheEntry; // rbx
char v18; // [rsp+30h] [rbp-28h]
v2 = a1;
if ( (unsigned int)lua_isnumber(a1, 1i64) )
{
questID = lua_tointeger(v2, 1i64);
completed = 0;
questEntryIndexInQuestLog = 0;
pQuestID = questID;
questLogEntryPtr = CGQuestLog::m_logEntries;
while ( questLogEntryPtr[2] & 1 || *questLogEntryPtr != questID )
{
++questEntryIndexInQuestLog;
questLogEntryPtr += 3;
if ( questEntryIndexInQuestLog >= 0x32 )
{
questEntryIndexInQuestLog = -1;
break;
}
}
ClntObjMgrGetActivePlayer(questID, (__int64)questLogEntryPtr);
if ( (unsigned int)CGQuestLog::IsQuestReadyForTurnin(activePlayerPtr, pQuestID, 1, 0, a2, 0) )
goto LABEL_26;
if ( questEntryIndexInQuestLog < CGQuestLog::m_numQuests )
{
startOfQuestLogEntry = 3i64 * questEntryIndexInQuestLog;
if ( !(CGQuestLog::m_logEntries[startOfQuestLogEntry + 2] & 1) )
{
ClntObjMgrGetActivePlayer(questEntryIndexInQuestLog, 3i64 * questEntryIndexInQuestLog);
if ( m_activePlayerPtr )
{
questIndex = CGQuestLog::m_logEntries[startOfQuestLogEntry + 1];
if ( (int)questIndex < 0 || (unsigned int)questIndex > 0x19 )
questInfoPtr = 0i64;
else
questInfoPtr = (questIndex << 6) + *(_QWORD *)(m_activePlayerPtr + 0xE9A0) + 0x54i64;
questIdFromLogEntry = &CGQuestLog::m_logEntries[startOfQuestLogEntry];
questGiverId = CGQuestInfo::GetRecentQuestGiverFor((__int64)&v18, *questIdFromLogEntry);
questCacheEntryResult = DBCache::GetRecord(
(__int64)&QuestsCacheBase,
questIdFromLogEntry,
questGiverId,
(void (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD))QuestQueryCallback,
0i64);
questCacheEntry = questCacheEntryResult;
if ( questCacheEntryResult )
{
if ( questInfoPtr
&& !(*(_BYTE *)(questCacheEntryResult + 0x60) & 6)
&& !(*(_BYTE *)(questInfoPtr + 4) & 2)
&& !QuestLogEntryHasFailed(questEntryIndexInQuestLog)
&& *(_QWORD *)(questCacheEntry + 0x2E28) <= 0ui64 )
{
LABEL_26:
completed = 1;
}
}
}
}
}
lua_pushboolean(v2, completed);
result = 1i64;
}
else
{
sub_58EE40(v2, (__int64)aUsageIsquestco);
result = 0i64;
}
return result;
}
__int64 __usercall CGQuestLog::IsQuestReadyForTurnin@<rax>(__int64 activePlayerPtr@<rcx>, __int64 questIdParam@<rdx>, char a3@<r8b>, int a4@<r9d>, float xmm0_4_0@<xmm0>, int a5)
{
int zeroInt; // er14
char aBoolean; // di
__int64 m_activePlayerPtr; // r15
__int64 v9; // rax
unsigned int v10; // ebx
__int64 questCacheEntryPtr; // rsi
unsigned int v12; // eax
__int64 playerQuestInfoPtr; // rdx
int *v15; // rax
char v16; // al
__int64 objectiveCount; // rax
__int64 QuestObjectivesStartPtr; // rbx
__int64 QuestObjectivesEndPtr; // rbp
int v20; // edi
__int64 QuestObjectiveTypePtr; // rbx
char v22; // [rsp+30h] [rbp-28h]
int localQuestId; // [rsp+68h] [rbp+10h]
localQuestId = questIdParam;
zeroInt = a4; // is zero
aBoolean = a3; // is 1
m_activePlayerPtr = activePlayerPtr;
if ( !activePlayerPtr )
return 0i64;
v9 = CGQuestInfo::GetRecentQuestGiverFor((__int64)&v22, questIdParam);
v10 = 0;
questCacheEntryPtr = DBCache::GetRecord(
(__int64)&QuestsCacheBase,
&localQuestId,
v9,
(void (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD))QuestQueryCallback,
0i64);
if ( !questCacheEntryPtr )
return 0i64;
if ( localQuestId )
{
v12 = 0;
playerQuestInfoPtr = *(_QWORD *)(m_activePlayerPtr + 0xE9A0) + 0x54i64;
while ( *(_DWORD *)playerQuestInfoPtr != localQuestId )
{
++v12;
playerQuestInfoPtr += 64i64;
if ( v12 >= 0x19 )
goto LABEL_7;
}
}
else
{
LABEL_7:
playerQuestInfoPtr = 0i64;
}
if ( (*(_DWORD *)(questCacheEntryPtr + 4) - 3) & 0xFFFFFFFD )
{
if ( !playerQuestInfoPtr )
return 0i64;
}
else if ( !playerQuestInfoPtr )
{
goto LABEL_14;
}
if ( *(_BYTE *)(playerQuestInfoPtr + 4) & 2 )
return 0i64;
LABEL_14:
if ( CGQuestLog::m_numQuests )
{
v15 = CGQuestLog::m_logEntries;
while ( *v15 != localQuestId )
{
++v10;
v15 += 3;
if ( v10 >= CGQuestLog::m_numQuests )
goto LABEL_21;
}
v16 = CGQuestLog::m_logEntries[3 * v10 + 2];
if ( !(v16 & 1) )
{
if ( v16 & 2 )
return 0i64;
}
}
LABEL_21:
if ( aBoolean && !*(_QWORD *)(questCacheEntryPtr + 0x2E28) && !(*(_BYTE *)(questCacheEntryPtr + 0x60) & 2)
|| *(_BYTE *)(questCacheEntryPtr + 0x60) & 2 && playerQuestInfoPtr && !(*(_BYTE *)(playerQuestInfoPtr + 4) & 1) )
{
return 0i64;
}
objectiveCount = *(_QWORD *)(questCacheEntryPtr + 0x2E28);
if ( objectiveCount )
{
QuestObjectivesStartPtr = *(_QWORD *)(questCacheEntryPtr + 0x2E20);
QuestObjectivesEndPtr = QuestObjectivesStartPtr + 312 * objectiveCount;
if ( QuestObjectivesStartPtr != QuestObjectivesEndPtr )
{
v20 = a5;
QuestObjectiveTypePtr = QuestObjectivesStartPtr + 4;
do
{
if ( QuestObjectiveTypePtr != 4 && !(*(_BYTE *)(QuestObjectiveTypePtr + 0xC) & 4) )
{
if ( *(_BYTE *)QuestObjectiveTypePtr == 1
&& zeroInt
&& v20
&& *(_DWORD *)(QuestObjectiveTypePtr + 4) == zeroInt )
{
if ( v20 < *(_DWORD *)(QuestObjectiveTypePtr + 8) )
return 0i64;
}
else if ( !CGQuestLog::IsQuestObjectiveComplete(
m_activePlayerPtr,
(__int64 *)questCacheEntryPtr,
QuestObjectiveTypePtr - 4,
xmm0_4_0) )
{
return 0i64;
}
}
QuestObjectiveTypePtr += 312i64; // size of quest objective struct
}
while ( QuestObjectiveTypePtr - 4 != QuestObjectivesEndPtr );
}
}
sub_163BE00(0x21u);
return 1i64;
}
char __usercall CGQuestLog::IsQuestObjectiveComplete@<al>(__int64 aPlayerPtr@<rcx>, __int64 *aQuestCahceEntryPtr@<rdx>, __int64 aObjectiveInfoPtr@<r8>, float a4@<xmm0>)
{
int objectiveType; // eax
__int64 v5; // r9
char result; // al
unsigned int questID; // ecx
unsigned int v8; // eax
_DWORD *questInfoPtr; // rdx
objectiveType = *(unsigned __int8 *)(aObjectiveInfoPtr + 4);
v5 = aPlayerPtr;
switch ( objectiveType )
{
case 0:
case 1:
case 2:
case 3:
case 9:
case 13:
case 16:
case 17:
case 18:
result = (int)GetQuestObjectiveFulfilledCount(
objectiveType,
*(_DWORD *)aQuestCahceEntryPtr,
aPlayerPtr,
aObjectiveInfoPtr) >= *(_DWORD *)(aObjectiveInfoPtr + 12);
break;
case 4:
result = PlayerHasEnoughCurrency(*(_DWORD *)(aObjectiveInfoPtr + 8), *(_DWORD *)(aObjectiveInfoPtr + 12));
break;
case 5:
result = PlayerLearnedSpell(aPlayerPtr, *(_DWORD *)(aObjectiveInfoPtr + 8));
break;
case 6:
result = (int)PlayerFactionReputation(*(_DWORD *)(aObjectiveInfoPtr + 8)) >= *(_DWORD *)(aObjectiveInfoPtr + 12);
break;
case 7:
result = (int)PlayerFactionReputation(*(_DWORD *)(aObjectiveInfoPtr + 8)) <= *(_DWORD *)(aObjectiveInfoPtr + 12);
break;
case 8:
if ( !((*(unsigned int *)((char *)&ObjectTypeFlags[*(unsigned __int8 *)(aPlayerPtr + 0x20)] + aPlayerPtr) >> 5) & 1) )
goto LABEL_13;
result = *(_QWORD *)(*(_QWORD *)(aPlayerPtr + 0x11EB8) + 0x870i64) >= (unsigned __int64)*(int *)(aObjectiveInfoPtr + 12);// only for local player
break;
case 10:
case 11:
case 12:
case 14:
case 19:
case 20:
questID = *(_DWORD *)aQuestCahceEntryPtr;
if ( *(_DWORD *)aQuestCahceEntryPtr )
{
v8 = 0;
questInfoPtr = (_DWORD *)(*(_QWORD *)(v5 + 0xE9A0) + 0x54i64);
while ( *questInfoPtr != questID )
{
++v8;
questInfoPtr += 16;
if ( v8 >= 0x19 )
goto LABEL_13;
}
result = ((256 << *(_BYTE *)(aObjectiveInfoPtr + 5)) & questInfoPtr[1]) != 0;
}
else
{
LABEL_13:
result = 0;
}
break;
case 15: // quest type: Progress Bar
sub_177DA40(aPlayerPtr, *(_DWORD *)aQuestCahceEntryPtr, aObjectiveInfoPtr, aPlayerPtr);
result = a4 >= *((float *)&xmmword_259A858 + 1);
break;
default:
result = 1;
break;
}
return result;
}
public enum QuestType
{
AutoComplete,
Disabled,
Enabled,
WorldQuest
}
[Flags]
public enum QuestFlags
{
None,
/// <summary>
/// If player dies, the quest fails
/// </summary>
StayAlive = 1,
/// <summary>
/// Escort quests or any other event-driven quests.
/// </summary>
Escort = 2,
/// <summary>
/// Involves the activation of an areatrigger
/// </summary>
Exploration = 4,
/// <summary>
/// Allows the quest to be shared with pther players.
/// </summary>
Sharable = 8,
/// <summary>
/// Either unknown or unused
/// </summary>
Unused = 16,
/// <summary>
/// Epic class quests?
/// </summary>
Epic = 32,
/// <summary>
/// Raid quests
/// </summary>
Raid = 64,
/// <summary>
/// TBC quests
/// </summary>
TBC = 128,
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct QuestObjectiveInfo
{
//size is 312 bytes
public int ID;
public QuestObjectiveType Type; //0x4
public byte ObjectiveIndex; //0x5, it is the objective index in the quest info
public short OrderIndex;//0x6, not sure about this
public uint ObjectId;//0x8
public uint Amount;//0xc
public QuestObjectiveFlags Flags;//0x10
public uint Flags2;//0x14, not sure about this
public float PercentAmount;//0x18, related to ProgressBar objectives
}
[Flags]
internal enum QuestObjectiveFlags : uint
{
None,
/// <summary>
/// Client displays large yellow blob on minimap for creature/gameobject
/// </summary>
TrackedOnMinimap = 1,
/// <summary>
/// Client will not see the objective displayed until all previous objectives are completed
/// </summary>
Sequenced = 2,
/// <summary>
/// Not required to complete the quest
/// </summary>
Optional = 4,
/// <summary>
/// Never displayed in quest log
/// </summary>
Hidden = 8,
/// <summary>
/// Skip showing item objective progress
/// </summary>
HideItemGains = 16,
/// <summary>
/// Item objective progress counts items in inventory instead of reading it from updatefields
/// </summary>
ProgressCountsItemInInventory = 32,
/// <summary>
/// Hidden objective used to calculate progress bar percent (quests are limited to a single progress bar objective)
/// </summary>
PartOfProgressBar = 64,
}
internal enum QuestObjectiveType : byte
{
Kill,
Collect,
InteractWithObject,
InteractWithUnit,
Currency,
LearnSpell,
MinReputtionWithFaction,
MaxReputtionWithFaction,
Money,
PlayerKills,
AreaTrigger,
DefeatBattlePetNPC,
DefeatBattlePet,
WinPvPBattle,
CriteriaTree,
ProgressBar,
HaveCurrency,
ObtainCurrency,
Type18,
Type19,
Type20,
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct QuestInfo
{
/* 0x00 */
public uint QuestId;
/* 0x04 */
public QuestState StateFlags;
/* 0x08 */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
public short[] ObjectiveProgress;
public int EndTime;
/* 0x0C */
public int AcceptTime;
/* 0x10 */
}
public enum QuestState : uint
{
None = 0,
Complete = 1,
Failed = 2
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct QuestLogEntry
{
public uint QuestID;
public uint QuestInfoIndex;
public QuestLogEntryFlags Flags;
}
[Flags]
public enum QuestLogEntryFlags : uint
{
NONE = 0,
Header = 1,
Failed = 2,
InProgress = 4,//not sure
Unk8 = 8,
Unk16 = 16,
Unk32 = 32,
}