////////////////////////////////////////////////////////////////////////////////////////////////////////////
////
//
// MQ2AutoClaim - Claim your free station cash
//
// Author : Dewey2461
//
// FILES: MQ2AutoClaim.INI - Used to store the "next" reward date.
//
// This was originally a macro, it was converted to a plugin so it will automatically run at startup.
// WARNING: Makes heavy use of ParseMacroData to Evaluate MQ2 macro code, you are free to refactor it.
// If you make changes please push the changes back to the author.
//
////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////
//
//
// IMPLEMENTATION NOTES:
//
// /echo ${Window[MKPW_ClaimWindow].Child[MKPW_ClaimDescription].Text}
//
// Option #1 - Reward expires:<br><c "#FFFF00">mm/dd/yy hh:mmPM</c> - Time to collect
// Option #2 - Next Reward: mm/dd/yy - Already collected
// Option #3 - Not a member? Click for details! - Not gold.
//
//
////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "../MQ2Plugin.h"
PreSetup("MQ2AutoClaim");
int PluginState = 0;
int DebugEvaluate = 0;
#define TIME unsigned long long
float Evaluate(char *zOutput, char *zFormat, ...) {
va_list vaList;
va_start(vaList, zFormat);
vsprintf_s(zOutput, MAX_STRING, zFormat, vaList);
if (DebugEvaluate) WriteChatf("Eval[%s]", zOutput);
char LastNormalError[MAX_STRING];
char LastSyntaxError[MAX_STRING];
char LastMQ2DataError[MAX_STRING];
strncpy_s(LastNormalError, gszLastNormalError, MAX_STRING);
strncpy_s(LastSyntaxError, gszLastSyntaxError, MAX_STRING);
strncpy_s(LastMQ2DataError, gszLastMQ2DataError, MAX_STRING);
gszLastNormalError[0] = gszLastSyntaxError[0] = gszLastMQ2DataError[0] = 0;
ParseMacroData(zOutput, MAX_STRING);
if (DebugEvaluate) WriteChatf("EvalResp[%s]", zOutput);
if (gszLastNormalError[0] || gszLastSyntaxError[0] || gszLastMQ2DataError[0]) {
char szTemp[MAX_STRING];
vsprintf_s(szTemp, MAX_STRING, zFormat, vaList);
if (gszLastNormalError[0]) WriteChatf("MQ2AutoClaim Error:[%s] on Evaluate[%s] = [%s]", gszLastNormalError, szTemp, zOutput);
if (gszLastSyntaxError[0]) WriteChatf("MQ2AutoClaim Error:[%s] on Evaluate[%s] = [%s]", gszLastSyntaxError, szTemp, zOutput);
if (gszLastMQ2DataError[0]) WriteChatf("MQ2AutoClaim Error:[%s] on Evaluate[%s] = [%s]", gszLastMQ2DataError, szTemp, zOutput);
gszLastNormalError[0] = gszLastSyntaxError[0] = gszLastMQ2DataError[0] = 0;
}
if (LastNormalError[0]) strncpy_s(gszLastNormalError, LastNormalError, MAX_STRING);
if (LastSyntaxError[0]) strncpy_s(gszLastSyntaxError, LastSyntaxError, MAX_STRING);
if (LastMQ2DataError[0]) strncpy_s(gszLastNormalError, LastMQ2DataError, MAX_STRING);
if (_stricmp(zOutput, "NULL") == 0) return 0;
if (_stricmp(zOutput, "FALSE") == 0) return 0;
if (_stricmp(zOutput, "TRUE") == 0) return 1;
return (float)atof(zOutput);
}
PLUGIN_API VOID InitializePlugin(VOID)
{
PluginState = 1;
}
PLUGIN_API VOID ShutdownPlugin(VOID)
{
}
PLUGIN_API VOID SetGameState(DWORD GameState)
{
if (gGameState == GAMESTATE_CHARSELECT) PluginState = 1;
}
// 01234567 0123456789
// mm/dd/yy or mm/dd/yyyy
void ParseDate(char *s, int &m, int &d, int &y)
{
m = d = y = 0;
int c = 1;
while (*s)
{
if (*s >= '0' && *s <= '9') {
switch (c) {
case 1: m = m * 10 + (*s - '0'); break;
case 2: d = d * 10 + (*s - '0'); break;
case 3: y = y * 10 + (*s - '0'); break;
}
}
if (*s == '/') c++;
s++;
}
if (y<100) y += 2000;
}
int CompareDates(char *s1, char *s2)
{
int m1, d1, y1;
int m2, d2, y2;
ParseDate(s1, m1, d1, y1);
ParseDate(s2, m2, d2, y2);
if (y1 != y2) return y1 - y2;
if (m1 != m2) return m1 - m2;
return d1 - d2;
}
// Doing all the heavy lifting in OnPulse via a State Machine "PluginState"
PLUGIN_API VOID OnPulse(VOID)
{
static TIME Tick = 0;
static TIME NextTick = 0;
static TIME AbortTick = 0;
static char szVal[MAX_STRING];
static char szDesc[MAX_STRING];
static char szName[MAX_STRING];
static char szCash[MAX_STRING];
static char szDate[MAX_STRING];
if (!PluginState) return;
if (gGameState != GAMESTATE_INGAME) return;
Tick = GetTickCount642();
if (Tick<NextTick) return;
if (Tick > AbortTick && PluginState != 1)
{
WriteChatf("[MQ2AutoClaim] Aborting... 120s should be plenty of time so something went wrong");
PluginState = 0;
return;
}
switch (PluginState) {
case 1:
PluginState = 0;
WriteChatf("\ag[MQ2AutoClaim]\aw Automatically claims your free station cash - Credit \ayDewey2461\aw");
if (Evaluate(szVal, "${Me.Subscription.NotEqual[GOLD]}")) {
WriteChatf("\ag[MQ2AutoClaim]\aw Account is not gold. No free station cash.");
return;
}
Evaluate(szName, "${EverQuest.LoginName}");
GetPrivateProfileString("NextCheck", szName, "01/01/2000", szDate, MAX_STRING, INIFileName);
Evaluate(szVal, "${Time.Date}");
if (CompareDates(szVal, szDate) < 0) {
WriteChatf("\ag[MQ2AutoClaim]\aw Next check scheduled for \ay%s\aw",szDate);
return;
}
// We are GOLD and NextCheck looks like we might have some SC ready.
DoCommand(NULL, "/if (!${Window[MarketplaceWnd]}) /market");
AbortTick = Tick + 120000;
PluginState = 2;
break;
case 2: // Wait for market place window to open and populate
Evaluate(szCash, "${Window[MarketplaceWnd].Child[MKPW_AvailableFundsUpper].Text}");
if (!szCash[0]) return;
Evaluate(szDesc, "${Window[MKPW_ClaimWindow].Child[MKPW_ClaimDescription].Text}");
if (!szDesc[0]) return;
if (strncmp(szDesc, "Reward expires:", 15) == 0) {
DoCommand(NULL, "/notify MKPW_ClaimWindow MKPW_ClaimClickHereBtn leftmouseup");
PluginState = 3;
return;
}
WriteChatf("\ag[MQ2AutoClaim]\aw Sorry, No free SC yet.");
PluginState = 4;
break;
case 3: // Wait for funds to update
Evaluate(szVal, "${Window[MarketplaceWnd].Child[MKPW_AvailableFundsUpper].Text}");
if (_stricmp(szVal, szCash) == 0) return;
WriteChatf("\ag[MQ2AutoClaim]\aw: Claimed your +500 free SC! You have \ay %s \aw SC.",szCash);
PluginState = 4;
break;
case 4:
Evaluate(szDesc, "${Window[MKPW_ClaimWindow].Child[MKPW_ClaimDescription].Text}");
// Match "Reward reward:<br><c "#FFFF00">mm/dd/yy hh:mmPM</c>"
if (strncmp(szDesc, "Next reward:", 12) == 0) {
szDesc[38] = 0;
WritePrivateProfileString("NextCheck", szName, &szDesc[29], INIFileName);
}
else { // Try again tomorrow
struct tm when;
__time64_t now;
time(&now);
_localtime64_s(&when, &now);
when.tm_mday = when.tm_mday + 1;
mktime(&when);
sprintf_s(szVal, "%0d/%02d/%02d", when.tm_mon+1,when.tm_mday,when.tm_year+1900);
WritePrivateProfileString("NextCheck", szName, szVal, INIFileName);
}
PluginState = 5;
break;
case 5:
DoCommand(NULL, "/if (${Window[MarketplaceWnd]}) /market");
PluginState = 0;
break;
}
}