// MQ2Etrack.cpp : Defines the entry point for the DLL application.
//
// PLUGIN_API is only to be used for callbacks. All existing callbacks at this time
// are shown below. Remove the ones your plugin does not use. Always use Initialize
// and Shutdown for setup and cleanup, do NOT do it in DllMain.
#include "../MQ2Plugin.h"
//Comment this if you don't want to use the EXP Window
#define EXP_WINDOW_ENABLE
PreSetup("MQ2Etrack");
class MQ2ExpType *pExpType=0;
class CExpWnd : public CCustomWnd {
public:
CExpWnd():CCustomWnd("ExpWindow") {
//Add each button here
RESETButton = (CButtonWnd*)GetChildItem("EXPButtonRESET");
SetWndNotification(CExpWnd);
}
~CExpWnd() {
}
int WndNotification(CXWnd *pWnd, unsigned int Message, void *unknown) {
//RESET Button
if (pWnd==(CXWnd*)RESETButton) {
if (Message==XWM_LCLICK)
DoCommand((PSPAWNINFO)pCharSpawn,"/resetexp");
else
DebugSpew("RESETButton message %Xh / %d",Message,Message);
}
return CSidlScreenWnd::WndNotification(pWnd,Message,unkno wn);
};
CButtonWnd *RESETButton;
};
CExpWnd *MyWnd = NULL;
enum XP_TYPES {
regular,
alternate,
grouplead,
raidlead,
n_xp_types
};
struct _expdata {
int prev;
int gained;
int maxexp;
int lastexp;
char szetd[MAX_STRING];
} ge_expdata[n_xp_types];
int ge_level;
int ge_aapoints;
time_t ge_etdstart;
class MQ2ExpType : public MQ2Type
{
public:
enum ExpMembers {
Last=1,
Total,
LastAA,
TotalAA,
LastGroup,
TotalGroup,
LastRaid,
TotalRaid,
ETD,
ETDAA,
ETDGroup,
ETDRaid,
TotalTime
};
MQ2ExpType():MQ2Type("exp")
{
TypeMember(Last);
TypeMember(Total);
TypeMember(LastAA);
TypeMember(TotalAA);
TypeMember(LastGroup);
TypeMember(TotalGroup);
TypeMember(LastRaid);
TypeMember(TotalRaid);
TypeMember(ETD);
TypeMember(ETDAA);
TypeMember(ETDGroup);
TypeMember(ETDRaid);
TypeMember(TotalTime);
}
~MQ2ExpType()
{
}
bool GetMember(MQ2VARPTR VarPtr, PCHAR Member, PCHAR Index, MQ2TYPEVAR &Dest)
{
PMQ2TYPEMEMBER pMember=MQ2ExpType::FindMember(Member);
time_t tmp_t, seconds = time(NULL) - ge_etdstart;
struct tm *tmp_tm;
if (!pMember)
return false;
switch ((ExpMembers)pMember->ID)
{
case Last:
Dest.Float=
100.0f*ge_expdata[regular].lastexp/ge_expdata[regular].maxexp;
Dest.Type=pFloatType;
return true;
case Total:
Dest.Float=
100.0f*ge_expdata[regular].gained/ge_expdata[regular].maxexp;
Dest.Type=pFloatType;
return true;
case LastAA:
Dest.Float=
100.0f*ge_expdata[alternate].lastexp/ge_expdata[alternate].maxexp;
Dest.Type=pFloatType;
return true;
case TotalAA:
Dest.Float=
100.0f*ge_expdata[alternate].gained/ge_expdata[alternate].maxexp;
Dest.Type=pFloatType;
return true;
case LastGroup:
Dest.Float=
100.0f*ge_expdata[grouplead].lastexp/ge_expdata[grouplead].maxexp;
Dest.Type=pFloatType;
return true;
case TotalGroup:
Dest.Float=
100.0f*ge_expdata[grouplead].gained/ge_expdata[grouplead].maxexp;
Dest.Type=pFloatType;
return true;
case LastRaid:
Dest.Float=
100.0f*ge_expdata[raidlead].lastexp/ge_expdata[raidlead].maxexp;
Dest.Type=pFloatType;
return true;
case TotalRaid:
Dest.Float=
100.0f*ge_expdata[raidlead].gained/ge_expdata[raidlead].maxexp;
Dest.Type=pFloatType;
return true;
case ETD:
// note: year is fucked but i don't care. no one runs a
// macro for a year
if (ge_expdata[regular].gained) {
tmp_t = (ge_expdata[regular].maxexp-GetCharInfo()->Exp)*seconds/ge_expdata[regular].gained;
tmp_tm = gmtime(&tmp_t);
if (tmp_tm) {
tmp_tm->tm_mday--;
Dest.Type=pTimeType;
Dest.Ptr=tmp_tm;
return true;
} else {
return false;
}
} else {
return false;
}
case ETDAA:
if (ge_expdata[alternate].gained) {
tmp_t = (ge_expdata[alternate].maxexp-GetCharInfo()->AAExp)*seconds/ge_expdata[alternate].gained;
tmp_tm = gmtime(&tmp_t);
if (tmp_tm) {
tmp_tm->tm_mday--;
Dest.Type=pTimeType;
Dest.Ptr=tmp_tm;
return true;
} else {
return false;
}
} else {
return false;
}
case ETDGroup:
if (ge_expdata[grouplead].gained) {
tmp_t = (ge_expdata[grouplead].maxexp-GetCharInfo()->AAExp)*seconds/ge_expdata[grouplead].gained;
tmp_tm = gmtime(&tmp_t);
if (tmp_tm) {
tmp_tm->tm_mday--;
Dest.Type=pTimeType;
Dest.Ptr=tmp_tm;
return true;
} else {
return false;
}
} else {
return false;
}
case ETDRaid:
if (ge_expdata[raidlead].gained) {
tmp_t = (ge_expdata[raidlead].maxexp-GetCharInfo()->AAExp)*seconds/ge_expdata[raidlead].gained;
tmp_tm = gmtime(&tmp_t);
if (tmp_tm) {
tmp_tm->tm_mday--;
Dest.Type=pTimeType;
Dest.Ptr=tmp_tm;
return true;
} else {
return false;
}
} else {
return false;
}
case TotalTime:
tmp_tm = gmtime(&seconds);
if (tmp_tm) {
tmp_tm->tm_mday--;
Dest.Type=pTimeType;
Dest.Ptr=tmp_tm;
return true;
} else {
return false;
}
}
return false;
}
bool ToString(MQ2VARPTR VarPtr, PCHAR Destination)
{
return false;
}
bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
{
return false;
}
bool FromString(MQ2VARPTR &VarPtr, PCHAR Source)
{
return false;
}
};
BOOL dataExp(PCHAR szName, MQ2TYPEVAR &Ret)
{
Ret.DWord=1;
Ret.Type=pExpType;
return true;
}
DWORD parmExp(PCHAR szVar, PCHAR szOutput, PSPAWNINFO pChar)
{
DWORD i=0;
CHAR szBuffer[MAX_STRING]={0};
time_t tmp_t, seconds = time(NULL) - ge_etdstart;
struct tm *tmp_tm;
if (!strncmp("exp(last)", szVar, 9)) {
i+=8;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[regular].lastexp/ge_expdata[regular].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(total)", szVar, 10)) {
i+=9;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[regular].gained/ge_expdata[regular].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(last,aa)", szVar, 12)) {
i+=11;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[alternate].lastexp/ge_expdata[alternate].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(total,aa)", szVar, 13)) {
i+=12;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[alternate].gained/ge_expdata[alternate].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(last,group)", szVar, 15)) {
i+=14;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[grouplead].lastexp/ge_expdata[grouplead].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(total,group)", szVar, 16)) {
i+=15;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[grouplead].gained/ge_expdata[grouplead].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(last,raid)", szVar, 14)) {
i+=13;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[raidlead].lastexp/ge_expdata[raidlead].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(total,raid)", szVar, 15)) {
i+=14;
sprintf(szBuffer,"%3.1f%%",
100.0f*ge_expdata[raidlead].gained/ge_expdata[raidlead].maxexp);
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(etd)", szVar, 8)) {
i+=7;
if (ge_expdata[regular].gained) {
tmp_t = (ge_expdata[regular].maxexp-GetCharInfo()->Exp)*seconds/ge_expdata[regular].gained;
tmp_tm = gmtime(&tmp_t);
//days start as one if you use strftime
//strftime(szBuffer, sizeof(szBuffer), "%d days %H hr %M min %S sec", tmp_tm);
sprintf(szBuffer, "%d days %d hr %d min %d sec", tmp_tm->tm_mday-1, tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec);
} else {
sprintf(szBuffer,"forever");
}
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(etd,aa)", szVar, 11)) {
i+=10;
if (ge_expdata[alternate].gained) {
tmp_t = (ge_expdata[alternate].maxexp-GetCharInfo()->AAExp)*seconds/ge_expdata[alternate].gained;
tmp_tm = localtime(&tmp_t);
sprintf(szBuffer, "%d days %d hr %d min %d sec", tmp_tm->tm_mday-1, tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec);
} else {
sprintf(szBuffer,"forever");
}
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(etd,group)", szVar, 14)) {
i+=13;
if (ge_expdata[grouplead].gained) {
tmp_t = (ge_expdata[grouplead].maxexp-GetCharInfo()->AAExp)*seconds/ge_expdata[grouplead].gained;
tmp_tm = localtime(&tmp_t);
sprintf(szBuffer, "%d days %d hr %d min %d sec", tmp_tm->tm_mday-1, tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec);
} else {
sprintf(szBuffer,"forever");
}
strcat(szOutput,szBuffer);
} else if (!strncmp("exp(etd,raid)", szVar, 13)) {
i+=12;
if (ge_expdata[raidlead].gained) {
tmp_t = (ge_expdata[raidlead].maxexp-GetCharInfo()->AAExp)*seconds/ge_expdata[raidlead].gained;
tmp_tm = localtime(&tmp_t);
sprintf(szBuffer, "%d days %d hr %d min %d sec", tmp_tm->tm_mday-1, tmp_tm->tm_hour, tmp_tm->tm_min, tmp_tm->tm_sec);
} else {
sprintf(szBuffer,"forever");
}
strcat(szOutput,szBuffer);
}
return i;
}
/* "/resetexp" command */
void ResetExpCmd(PSPAWNINFO pChar, PCHAR szLine)
{
PCHARINFO pCharInfo = GetCharInfo();
PCHARINFO2 pCharInfo2 = GetCharInfo2();
ge_level = pCharInfo2->Level;
ge_aapoints = pCharInfo2->AAPoints;
ge_expdata[regular].gained = 0;
ge_expdata[regular].maxexp = 330;
ge_expdata[regular].prev = pCharInfo->Exp;
ge_expdata[regular].lastexp = 0;
ge_expdata[alternate].gained = 0;
ge_expdata[alternate].maxexp = 330;
ge_expdata[alternate].prev = pCharInfo->AAExp;
ge_expdata[alternate].lastexp = 0;
ge_expdata[grouplead].gained = 0;
ge_expdata[grouplead].maxexp = 500;
ge_expdata[grouplead].prev = pCharInfo->GroupLeadershipExp;
ge_expdata[grouplead].lastexp = 0;
ge_expdata[raidlead].gained = 0;
ge_expdata[raidlead].maxexp = 900;
ge_expdata[raidlead].prev = pCharInfo->RaidLeadershipExp;
ge_expdata[raidlead].lastexp = 0;
ge_etdstart = time(NULL);
}
/* "/showexp" command */
void ShowExpCmd(PSPAWNINFO pChar, PCHAR szLine)
{
char str[1024];
sprintf(str, "Current Level: \ar%d\ax", ge_level);
WriteChatColor(str);
sprintf(str, "Current Exp Gained: \ar%d\ax", ge_expdata[regular].gained);
WriteChatColor(str);
sprintf(str, "Current G-LDR Gained: \ar%d\ax", ge_expdata[grouplead].gained);
WriteChatColor(str);
sprintf(str, "Current R-LDR Gained: \ar%d\ax", ge_expdata[raidlead].gained);
WriteChatColor(str);
sprintf(str, "Current AA Gained: \ar%d\ax", ge_expdata[alternate].gained);
WriteChatColor(str);
}
// Called once, when the plugin is to initialize
PLUGIN_API VOID InitializePlugin(VOID)
{
DebugSpewAlways("Initializing MQ2Etrack");
#ifdef EXP_WINDOW_ENABLE
AddXMLFile("MQUI_ExpWnd.xml");
// don't do a window when the plugin is initialized. who knows what
// state we are in...
#if 0
if (!MyWnd) {
DebugTry(CScreenPieceTemplate *templ=pSidlMgr->FindScreenPieceTemplate("ExpWindow"));
if (templ) MyWnd=new CExpWnd;
}
#endif
AddCommand("/showexp",ShowExpCmd);
#endif
//AddParm("exp",parmExp);
AddMQ2Data("Exp", dataExp);
AddCommand("/resetexp",ResetExpCmd);
pExpType = new MQ2ExpType;
}
// Called once, when the plugin is to shutdown
PLUGIN_API VOID ShutdownPlugin(VOID)
{
DebugSpewAlways("Shutting down MQ2Etrack");
if (MyWnd) {
delete MyWnd;
MyWnd=NULL;
}
#ifdef EXP_WINDOW_ENABLE
RemoveXMLFile("MQUI_ExpWnd.xml");
RemoveCommand("/showexp");
#endif
RemoveCommand("/resetexp");
//RemoveParm("exp");
RemoveMQ2Data("exp");
delete pExpType;
}
// Called after entering a new zone
PLUGIN_API VOID OnZoned(VOID)
{
DebugSpewAlways("MQ2Etrack::OnZoned()");
ResetExpCmd(NULL, NULL);
}
// Called once directly before shutdown of the new ui system, and also
// every time the game calls CDisplay::CleanGameUI()
PLUGIN_API VOID OnCleanUI(VOID)
{
DebugSpewAlways("MQ2Etrack::OnCleanUI()");
if (MyWnd) {
delete MyWnd;
MyWnd=NULL;
}
}
// Called once directly after the game ui is reloaded, after issuing /loadskin
PLUGIN_API VOID OnReloadUI(VOID)
{
DebugSpewAlways("MQ2Etrack::OnReloadUI()");
#ifdef EXP_WINDOW_ENABLE
if (!MyWnd) {
DebugTry(CScreenPieceTemplate *templ=pSidlMgr->FindScreenPieceTemplate("ExpWindow"));
if (templ) MyWnd=new CExpWnd;
}
#endif
ResetExpCmd(NULL, NULL);
}
// Called once directly after initialization, and then every time the gamestate changes
PLUGIN_API VOID SetGameState(DWORD GameState)
{
DebugSpewAlways("MQ2Etrack::SetGameState()");
// if (GameState==GAMESTATE_INGAME)
// create custom windows if theyre not set up, etc
}
// This is called every time EQ shows a line of chat with CEverQuest::dsp_chat,
// but after MQ filters and chat events are taken care of.
PLUGIN_API DWORD OnIncomingChat(PCHAR Line, DWORD Color)
{
PCHARINFO pCharInfo = GetCharInfo();
PCHARINFO2 pCharInfo2 = GetCharInfo2();
DebugSpewAlways("MQ2Etrack::OnIncomingChat(%s)",Line);
// did we level?
if (ge_level != pCharInfo2->Level) {
ge_level = pCharInfo2->Level;
ge_expdata[regular].gained = pCharInfo->Exp + (330 - ge_expdata[regular].prev);
// didn't level, but did we get xp?
} else if (ge_expdata[regular].prev != pCharInfo->Exp) {
ge_expdata[regular].lastexp = pCharInfo->Exp - ge_expdata[regular].prev;
ge_expdata[regular].gained += ge_expdata[regular].lastexp;
}
// are we getting AA?
if(pCharInfo->PercentEXPtoAA != 0) {
// if we got a new point, prev should be just below 330...
if (ge_aapoints != pCharInfo2->AAPoints) {
ge_expdata[alternate].lastexp = pCharInfo->AAExp + (330-ge_expdata[alternate].prev);
ge_expdata[alternate].gained += ge_expdata[alternate].lastexp;
} else if (ge_expdata[alternate].prev != pCharInfo->AAExp) {
ge_expdata[alternate].lastexp = pCharInfo->AAExp - ge_expdata[alternate].prev;
ge_expdata[alternate].gained += ge_expdata[alternate].lastexp;
}
}
// this may be done like AA points but for now we'll
// do it straight up
if (ge_expdata[grouplead].prev != pCharInfo->GroupLeadershipExp) {
ge_expdata[grouplead].lastexp = pCharInfo->GroupLeadershipExp - ge_expdata[grouplead].prev;
ge_expdata[grouplead].gained += ge_expdata[grouplead].lastexp;
}
if (ge_expdata[raidlead].prev != pCharInfo->RaidLeadershipExp) {
ge_expdata[raidlead].lastexp = pCharInfo->RaidLeadershipExp - ge_expdata[raidlead].prev;
ge_expdata[raidlead].gained += ge_expdata[raidlead].lastexp;
}
ge_expdata[regular].prev = pCharInfo->Exp;
ge_expdata[alternate].prev = pCharInfo->AAExp;
ge_expdata[grouplead].prev = pCharInfo->GroupLeadershipExp;
ge_expdata[raidlead].prev = pCharInfo->RaidLeadershipExp;
ge_aapoints = pCharInfo2->AAPoints;
return 0;
}