You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
966 lines
29 KiB
966 lines
29 KiB
#include "WatchEXP.h" |
|
#include "CommandParse.h" |
|
|
|
WatchEXP::WatchEXP(void) |
|
: m_AshitaCore(nullptr) |
|
, m_PluginId(0) |
|
, m_Direct3DDevice(nullptr) |
|
, m_ExpObj(nullptr) |
|
, m_AbyTimeStart(0) |
|
, m_DynTimeStart(0) |
|
, m_BaseTimeEXP(0) |
|
, m_BaseTimeCR(0) |
|
, m_resetTime(NULL) |
|
, font_size(0) |
|
, m_reset_min(0) |
|
, m_CurrentZoneID(0) |
|
, m_LastZoneRecorded(0) |
|
, m_Dyna_Crm('X') |
|
, m_Dyna_Azr('X') |
|
, m_Dyna_Amb('X') |
|
, m_Dyna_Alab('X') |
|
, m_Dyna_Obs('X') |
|
, m_vTime(0) |
|
, m_DynaTime(0) |
|
, m_xpKill(0) |
|
, m_xpTotal(0) |
|
, m_xpTest(0) |
|
, m_crKill(0) |
|
, m_crTotal(0) |
|
, m_prl(0) |
|
, m_gld(0) |
|
, m_slv(0) |
|
, m_ebn(0) |
|
, m_azr(0) |
|
, m_rby(0) |
|
, m_amb(0) |
|
, backTrans(0) |
|
, m_IsInAbyssea(false) |
|
, m_IsInDynamis(false) |
|
, show_XP_M_always(false) |
|
, m_autoreset(false) |
|
{ } |
|
WatchEXP::~WatchEXP(void) |
|
{ } |
|
|
|
plugininfo_t WatchEXP::GetPluginInfo(void) |
|
{ |
|
return *g_PluginInformation; |
|
} |
|
|
|
bool WatchEXP::Initialize(IAshitaCore* core, ILogManager* log, uint32_t id) |
|
{ |
|
// Store the variables we are passed.. |
|
this->m_AshitaCore = core; |
|
this->m_PluginId = id; |
|
|
|
this->GetConfig(); |
|
|
|
return true; |
|
} |
|
|
|
void WatchEXP::Release(void) |
|
{ |
|
} |
|
|
|
bool WatchEXP::HandleCommand(const char* pszCommand, int nCommandType) |
|
{ |
|
if (pszCommand == nullptr) |
|
return false; |
|
|
|
if (_strnicmp(pszCommand, "/wexp", 4) == 0) |
|
{ |
|
std::vector<std::string> args; |
|
Ashita::Commands::GetCommandArgs(pszCommand, &args); |
|
|
|
if (args[1] == "reset") |
|
{ |
|
m_crTotal = 0, m_xpTotal = 0, m_xpKill = 0, m_crKill = 0; |
|
m_BaseTimeEXP = time(nullptr), m_BaseTimeCR = time(nullptr); |
|
|
|
m_AshitaCore->GetChatManager()->Write("WatchEXP was reset!"); |
|
return true; |
|
} |
|
if (args[1] == "config") |
|
{ |
|
this->GetConfig(); |
|
m_ExpObj->SetFontFamily(font_name); |
|
m_ExpObj->SetFontHeight(font_size); |
|
|
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
//bool WatchEXP::HandleNewChatLine(short sMode, char* pszChatLine) |
|
bool WatchEXP::HandleIncomingText(int16_t sMode, const char* pszChatLine, int16_t* modifiedMode, char* modifiedMessage, bool blocked) |
|
{ |
|
std::string data; |
|
std::vector< std::string > temp; |
|
|
|
data = ScrubChat(pszChatLine); |
|
|
|
//Holds matches |
|
std::smatch m; |
|
|
|
#pragma region Search Pattern |
|
//Regex Searches |
|
std::regex xp_inc("gains\\s\\d+\\s(experience|limit)\\spoints"); |
|
std::regex xp_chain("EXP\\schain\\s\\d+\\s\\w+\\sgains\\s\\d+\\sexperience\\spoints"); |
|
std::regex cru_inc("obtained\\s\\d+\\scruor", std::regex_constants::icase); |
|
std::regex vis_wear("Your\\svisitant\\sstatus\\swill\\swear\\soff\\sin\\s\\d+\\sminutes"); |
|
std::regex vis_inc("Your\\svisitant\\sstatus\\shas\\sbeen\\sextended\\sby\\s\\d+\\sminutes"); |
|
std::regex vis_exit("Exiting\\sin\\s\\d+\\sminutes"); |
|
std::regex vis_pegs("Visitant\\sLight\\sIntensity\\sPearlescent\\s\\d+\\sEbon\\s\\d+\\sGolden\\s\\d+\\sSilvery\\s\\d+"); |
|
std::regex vis_azram("Azure\\s\\d+\\sRuby\\s\\d+\\sAmber\\s\\d+"); |
|
std::regex light_pearl("body\\semits\\sa\\sfaint\\spearlescent\\slight"); |
|
std::regex light_azure("body\\semits\\sa\\sfeeble\\sazure\\slight"); |
|
std::regex light_ruby("body\\semits\\sa\\sfeeble\\sruby\\slight"); |
|
std::regex light_amber("body\\semits\\sa\\sfeeble\\samber\\slight"); |
|
std::regex light_gold("body\\semits\\sa\\sfaint\\sgolden\\slight"); |
|
std::regex light_silver("body\\semits\\sa\\sfaint\\ssilvery\\slight"); |
|
std::regex light_ebon("body\\semits\\sa\\sfaint\\sebon\\slight"); |
|
std::regex dyn_start("sands"); |
|
std::regex dyn_start2("hourglass"); |
|
std::regex dyn_extend("Dynamis"); |
|
std::regex dyn_extend2("extended"); |
|
std::regex dyn_expelled("expelled"); |
|
|
|
//Used to get all the numbers |
|
std::regex get_number("\\d+"); |
|
|
|
if (sMode == 121) |
|
{ |
|
if (std::regex_search(data, xp_chain)) |
|
{ |
|
std::sregex_token_iterator start(data.begin(), data.end(), get_number, 0), end; |
|
|
|
while (start != end) |
|
{ |
|
temp.push_back(*start); |
|
++start; |
|
} |
|
|
|
if (temp.size() >= 1) |
|
m_xpKill = std::stoi(temp[temp.size() - 1]); |
|
else |
|
m_xpKill = 0; |
|
|
|
m_xpTotal += m_xpKill; |
|
} |
|
} |
|
if (sMode == 131) |
|
{ |
|
if (std::regex_search(data, xp_inc)) |
|
{ |
|
std::sregex_token_iterator start(data.begin(), data.end(), get_number, 0), end; |
|
temp.clear(); |
|
|
|
while (start != end) |
|
{ |
|
temp.push_back(*start); |
|
++start; |
|
} |
|
|
|
if (temp.size() >= 1) |
|
m_xpKill = std::stoi(temp[temp.size() - 1]); |
|
else |
|
m_xpKill = 0; |
|
|
|
m_xpTotal += m_xpKill; |
|
} |
|
} |
|
else if (sMode == 633) |
|
{ |
|
if (std::regex_search(data, cru_inc)) |
|
{ |
|
std::sregex_token_iterator start(data.begin(), data.end(), get_number, 0), end; |
|
temp.clear(); |
|
|
|
while (start != end) |
|
{ |
|
temp.push_back(*start); |
|
++start; |
|
} |
|
|
|
if (temp.size() >= 1) |
|
m_crKill = std::stoi(temp[temp.size() - 1]); |
|
else |
|
m_crKill = 0; |
|
|
|
m_crTotal += m_crKill; |
|
} |
|
else if (std::regex_search(data, vis_inc)) |
|
{ |
|
m_vTime += 10; |
|
} |
|
} |
|
else if (sMode == 653) |
|
{ |
|
if ((std::regex_search(data, dyn_expelled)) && (std::regex_search(data, dyn_extend))) |
|
{ |
|
std::regex_search(data, m, get_number); |
|
|
|
m_DynaTime = std::stoi(m.str()); |
|
|
|
m_DynTimeStart = time(nullptr); |
|
} |
|
} |
|
else if (sMode == 658) |
|
{ |
|
if ((std::regex_search(data, dyn_extend)) && (std::regex_search(data, dyn_extend2))) |
|
{ |
|
std::regex_search(data, m, get_number); |
|
|
|
m_DynaTime += std::stoi(m.str()); |
|
|
|
m_DynTimeStart = time(nullptr); |
|
} |
|
} |
|
else if (sMode == 660) |
|
{ |
|
if ((std::regex_search(data, dyn_start)) && (std::regex_search(data, dyn_start2))) |
|
{ |
|
std::regex_search(data, m, get_number); |
|
|
|
m_DynaTime = std::stoi(m.str()); |
|
} |
|
if (std::regex_search(data, vis_exit)) |
|
{ |
|
std::regex_search(data, m, get_number); |
|
|
|
m_vTime = std::stoi(m.str()); |
|
} |
|
else if (std::regex_search(data, cru_inc)) |
|
{ |
|
std::regex_search(data, m, get_number); |
|
m_crKill = std::stoi(m.str()); |
|
|
|
m_crTotal += m_crKill; |
|
} |
|
else if (std::regex_search(data, vis_wear)) |
|
{ |
|
std::regex_search(data, m, get_number); |
|
m_vTime = std::stoi(m.str()); |
|
|
|
m_AbyTimeStart = time(nullptr); |
|
} |
|
else if (std::regex_search(data, vis_pegs)) |
|
{ |
|
std::sregex_token_iterator start(data.begin(), data.end(), get_number, 0), end; |
|
|
|
while (start != end) |
|
{ |
|
temp.push_back(*start); |
|
++start; |
|
} |
|
|
|
//Corrects Pearlescent Values |
|
m_prl = std::stoi(temp[0]); |
|
|
|
//Corrects Ebon Values |
|
m_ebn = std::stoi(temp[1]); |
|
|
|
//Corrects Gold Values |
|
m_gld = std::stoi(temp[2]); |
|
|
|
//Corrects Silvery Values |
|
m_slv = std::stoi(temp[3]); |
|
|
|
} |
|
else if (std::regex_search(data, vis_azram)) |
|
{ |
|
std::sregex_token_iterator start(data.begin(), data.end(), get_number, 0), end; |
|
|
|
while (start != end) |
|
{ |
|
temp.push_back(*start); |
|
++start; |
|
} |
|
|
|
//Corrects Azure Values |
|
m_azr = std::stoi(temp[0]); |
|
|
|
//Corrects Ruby Values |
|
m_rby = std::stoi(temp[1]); |
|
|
|
//Corrects Amber Values |
|
m_amb = std::stoi(temp[2]); |
|
|
|
} |
|
else if (std::regex_search(data, light_pearl)) |
|
{ |
|
//checks to ensure value does not exceed 230 |
|
if (m_prl + 5 > 230) |
|
{ |
|
m_prl = 230; |
|
} |
|
else |
|
{ |
|
m_prl += 5; |
|
} |
|
} |
|
else if (std::regex_search(data, light_gold)) |
|
{ |
|
//checks to ensure value does not exceed 200 |
|
if (m_gld + 5 > 200) |
|
{ |
|
m_gld = 200; |
|
} |
|
else |
|
{ |
|
m_gld += 5; |
|
} |
|
} |
|
else if (std::regex_search(data, light_silver)) |
|
{ |
|
//checks to ensure value does not exceed 200 |
|
if (m_slv + 5 > 200) |
|
{ |
|
m_slv = 200; |
|
} |
|
else |
|
{ |
|
m_slv += 5; |
|
} |
|
} |
|
else if (std::regex_search(data, light_ebon)) |
|
{ |
|
//checks to ensure value does not exceed 200 |
|
if (m_ebn + 1 > 200) |
|
{ |
|
m_ebn = 200; |
|
} |
|
else |
|
{ |
|
m_ebn += 1; |
|
} |
|
} |
|
else if (std::regex_search(data, light_azure)) |
|
{ |
|
//checks to ensure value does not exceed 255 |
|
if (m_azr + 8 > 255) |
|
{ |
|
m_azr = 255; |
|
} |
|
else |
|
{ |
|
m_azr += 8; |
|
} |
|
} |
|
else if (std::regex_search(data, light_ruby)) |
|
{ |
|
//checks to ensure value does not exceed 255 |
|
if (m_rby + 8 > 255) |
|
{ |
|
m_rby = 255; |
|
} |
|
else |
|
{ |
|
m_rby += 8; |
|
} |
|
} |
|
else if (std::regex_search(data, light_amber)) |
|
{ |
|
//checks to ensure value does not exceed 255 |
|
if (m_amb + 8 > 255) |
|
{ |
|
m_amb = 255; |
|
} |
|
else |
|
{ |
|
m_amb += 8; |
|
} |
|
} |
|
} |
|
#pragma endregion |
|
|
|
return false; |
|
} |
|
|
|
bool WatchEXP::Direct3DInitialize(IDirect3DDevice8* lpDevice) |
|
{ |
|
this->m_Direct3DDevice = lpDevice; |
|
|
|
m_ExpObj = m_AshitaCore->GetFontManager()->Create("EXP_ID"); |
|
m_ExpObj->SetText("0/0"); |
|
m_ExpObj->SetFontFamily(font_name); |
|
m_ExpObj->SetFontHeight(font_size); |
|
m_ExpObj->SetColor(0xFFFFFFFF); |
|
m_ExpObj->SetBold(false); |
|
m_ExpObj->SetVisibility(true); |
|
m_ExpObj->SetPositionX(100); |
|
m_ExpObj->SetPositionY(100); |
|
m_ExpObj->SetVisibility(false); |
|
|
|
m_ExpObj->GetBackground()->SetVisibility(true); |
|
m_ExpObj->GetBackground()->SetColor(0x80000000); |
|
|
|
m_BaseTimeEXP = time(nullptr); |
|
m_BaseTimeCR = time(nullptr); |
|
|
|
return true; |
|
} |
|
|
|
void WatchEXP::Direct3DRelease(void) |
|
{ |
|
m_AshitaCore->GetFontManager()->Delete("EXP_ID"); |
|
} |
|
|
|
void WatchEXP::Direct3DRender(void) |
|
{ |
|
doEXPCalculations(); |
|
doAbysseaZoneTimings(); |
|
doDynamisZoneTimings(); |
|
checkResetTime(); |
|
} |
|
|
|
__declspec(dllexport) double __stdcall GetInterfaceVersion(void) |
|
{ |
|
return ASHITA_INTERFACE_VERSION; |
|
} |
|
|
|
__declspec(dllexport) void __stdcall CreatePluginInfo(plugininfo_t* info) |
|
{ |
|
g_PluginInformation = info; |
|
|
|
strcpy_s(info->Author, sizeof(info->Author), "Praenuntiae (ported by Vicrelant)"); |
|
strcpy_s(info->Name, sizeof(info->Name), "WatchEXP"); |
|
info->InterfaceVersion = ASHITA_INTERFACE_VERSION; |
|
info->PluginVersion = 3.0f; |
|
info->Priority = 0; |
|
} |
|
|
|
__declspec(dllexport) IPlugin* __stdcall CreatePlugin(void) |
|
{ |
|
return (IPlugin*)new WatchEXP(); |
|
} |
|
|
|
#pragma region GetConfig |
|
void WatchEXP::GetConfig() |
|
{ |
|
auto iConfigResult = false; |
|
auto iTemp = 0; |
|
|
|
iConfigResult = m_AshitaCore->GetConfigurationManager()->Load("WatchEXP", "WatchEXP"); |
|
|
|
if (iConfigResult != 0) |
|
{ |
|
auto szBuffer = m_AshitaCore->GetConfigurationManager()->get_string("WatchEXP", "font_name"); |
|
strcpy_s(font_name, szBuffer); |
|
|
|
font_size = m_AshitaCore->GetConfigurationManager()->get_int32("WatchEXP", "font_size", 11); |
|
show_XP_M_always = m_AshitaCore->GetConfigurationManager()->get_bool("WatchEXP", "show_both_xp_and_merits_when_capped", false); |
|
m_reset_min = m_AshitaCore->GetConfigurationManager()->get_int32("WatchEXP", "auto_reset_time", 45); |
|
m_autoreset = m_AshitaCore->GetConfigurationManager()->get_bool("WatchEXP", "auto_reset_enabled", false); |
|
} |
|
else if (iConfigResult == 0) |
|
{ |
|
m_AshitaCore->GetConfigurationManager()->set_value("WatchEXP", "font_name", "Arial"); |
|
m_AshitaCore->GetConfigurationManager()->set_value("WatchEXP", "font_size", "11"); |
|
m_AshitaCore->GetConfigurationManager()->set_value("WatchEXP", "show_both_xp_and_merits_when_capped", "true"); |
|
m_AshitaCore->GetConfigurationManager()->set_value("WatchEXP", "auto_reset_time", "45"); |
|
m_AshitaCore->GetConfigurationManager()->set_value("WatchEXP", "auto_reset_enabled", "false"); |
|
m_AshitaCore->GetConfigurationManager()->Save("WatchEXP", "WatchEXP"); |
|
|
|
strcpy_s(font_name, "Arial"); |
|
font_size = 11; |
|
show_XP_M_always = false; |
|
m_reset_min = 45; |
|
m_autoreset = false; |
|
} |
|
} |
|
#pragma endregion |
|
|
|
#pragma region doEXPCalculations |
|
void WatchEXP::doEXPCalculations() |
|
{ |
|
char *p; |
|
char expIntoLVL[10] = "", expForLVL[10] = "", expTillLVL[10] = "", lmtIntoLVL[10] = "", lmtTillLVL[10] = "", xpTotal[40] = "", crTotal[40] = ""; |
|
|
|
m_IsInAbyssea = isInAbyssea(m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0)); |
|
m_IsInDynamis = isInDynamis(m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0)); |
|
|
|
// get the EXP info |
|
unsigned short expIN = m_AshitaCore->GetDataManager()->GetPlayer()->GetExpCurrent(); |
|
unsigned short expMAX = m_AshitaCore->GetDataManager()->GetPlayer()->GetExpNeeded(); |
|
unsigned short expLEFT = expMAX - expIN; |
|
|
|
// get the Merit info |
|
unsigned short lmtIN = m_AshitaCore->GetDataManager()->GetPlayer()->GetLimitPoints(); |
|
unsigned short lmtMAX = 10000; |
|
unsigned short lmtLEFT = lmtMAX - lmtIN; |
|
|
|
p = expIntoLVL; |
|
makeComma(expIN, p, 0); |
|
_strrev(expIntoLVL); |
|
|
|
p = expForLVL; |
|
makeComma(expMAX, p, 0); |
|
_strrev(expForLVL); |
|
|
|
p = expTillLVL; |
|
makeComma(expLEFT, p, 0); |
|
_strrev(expTillLVL); |
|
|
|
p = lmtIntoLVL; |
|
makeComma(lmtIN, p, 0); |
|
_strrev(lmtIntoLVL); |
|
|
|
p = lmtTillLVL; |
|
makeComma(lmtLEFT, p, 0); |
|
_strrev(lmtTillLVL); |
|
|
|
p = xpTotal; |
|
makeComma(m_xpTotal, p, 0); |
|
_strrev(xpTotal); |
|
|
|
p = crTotal; |
|
makeComma(m_crTotal, p, 0); |
|
_strrev(crTotal); |
|
|
|
if (m_AshitaCore->GetDataManager()->GetPlayer()->GetMainJobLevel() < 75) |
|
{ |
|
if (m_IsInDynamis) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) XP:%s(%u) %.1fk/hr Alb:%c Amb:%c Azr:%c Crm:%c Obn:%c Time Remaining: %d ", expIntoLVL, expForLVL, expTillLVL, |
|
xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), m_Dyna_Alab, m_Dyna_Amb, m_Dyna_Azr, m_Dyna_Crm, m_Dyna_Obs, m_DynaTime); |
|
} |
|
else if (m_IsInAbyssea) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) XP:%s(%u) %.1fk/hr Cruor:%s(%u) %.1fk/hr Prl:%u Gld:%u Slv:%u Ebn:%u Azr:%u Rby:%u Amb:%u V.Time: %d ", |
|
expIntoLVL, expForLVL, expTillLVL, xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), crTotal, m_crKill, returnProjectedCRUORperHour(m_crTotal), |
|
m_prl, m_gld, m_slv, m_ebn, m_azr, m_rby, m_amb, m_vTime); |
|
} |
|
else |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) XP:%s(%u) %.1fk/hr ", expIntoLVL, expForLVL, expTillLVL, |
|
xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal)); |
|
} |
|
} |
|
if ((!show_XP_M_always) && (m_AshitaCore->GetDataManager()->GetPlayer()->GetMainJobLevel() >= 75)) |
|
{ |
|
unsigned char isMeritMode = m_AshitaCore->GetDataManager()->GetPlayer()->GetLimitMode(); |
|
|
|
if ((expLEFT == 1) || (isMeritMode == 224)) |
|
{ |
|
if (m_IsInDynamis) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/10,000(%s)[%i] XP:%s(%u) %.1fk/hr Alb:%c Amb:%c Azr:%c Crm:%c Obn:%c Time Remaining: %d ", lmtIntoLVL, lmtTillLVL, |
|
(int)m_AshitaCore->GetDataManager()->GetPlayer()->GetMeritPoints(), xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), m_Dyna_Alab, m_Dyna_Amb, m_Dyna_Azr, m_Dyna_Crm, |
|
m_Dyna_Obs, m_DynaTime); |
|
} |
|
else if (m_IsInAbyssea) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/10,000(%s)[%i] XP:%s(%u) %.1fk/hr Cruor:%s(%u) %.1fk/hr Prl:%u Gld:%u Slv:%u Ebn:%u Azr:%u Rby:%u Amb:%u V.Time: %d ", lmtIntoLVL, lmtTillLVL, |
|
(int)m_AshitaCore->GetDataManager()->GetPlayer()->GetMeritPoints(), xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), crTotal, m_crKill, returnProjectedCRUORperHour(m_crTotal), |
|
m_prl, m_gld, m_slv, m_ebn, m_azr, m_rby, m_amb, m_vTime); |
|
} |
|
else |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/10,000(%s)[%i] XP:%s(%u) %.1fk/hr ", |
|
lmtIntoLVL, lmtTillLVL, (int)m_AshitaCore->GetDataManager()->GetPlayer()->GetMeritPoints(), xpTotal, |
|
m_xpKill, returnProjectedEXPperHour(m_xpTotal)); |
|
} |
|
} |
|
else |
|
{ |
|
if (m_IsInDynamis) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) XP:%s(%u) %.1fk/hr Alb:%c Amb:%c Azr:%c Crm:%c Obn:%c Time Remaining: %d ", expIntoLVL, expForLVL, expTillLVL, |
|
xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), m_Dyna_Alab, m_Dyna_Amb, m_Dyna_Azr, m_Dyna_Crm, m_Dyna_Obs, m_DynaTime); |
|
} |
|
else if (m_IsInAbyssea) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) XP:%s(%u) %.1fk/hr Cruor:%s(%u) %.1fk/hr Prl:%u Gld:%u Slv:%u Ebn:%u Azr:%u Rby:%u Amb:%u V.Time: %d ", |
|
expIntoLVL, expForLVL, expTillLVL, xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), crTotal, m_crKill, returnProjectedCRUORperHour(m_crTotal), m_prl, |
|
m_gld, m_slv, m_ebn, m_azr, m_rby, m_amb, m_vTime); |
|
} |
|
else |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) XP:%s(%u) %.1fk/hr ", expIntoLVL, expForLVL, expTillLVL, xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal)); |
|
} |
|
} |
|
} |
|
if ((show_XP_M_always) && (m_AshitaCore->GetDataManager()->GetPlayer()->GetMainJobLevel() >= 75)) |
|
{ |
|
if (m_IsInDynamis) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) %s/10,000(%s)[%i] XP:%s(%u) %.1fk/hr Alb:%c Amb:%c Azr:%c Crm:%c Obn:%c Time Remaining: %d ", expIntoLVL, expForLVL, expTillLVL, |
|
lmtIntoLVL, lmtTillLVL, (int)m_AshitaCore->GetDataManager()->GetPlayer()->GetMeritPoints(), xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), m_Dyna_Alab, m_Dyna_Amb, |
|
m_Dyna_Azr, m_Dyna_Crm, m_Dyna_Obs, m_DynaTime); |
|
} |
|
else if (m_IsInAbyssea) |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) %s/10,000(%s)[%i] XP:%s(%u) %.1fk/hr Cruor:%s(%u) %.1fk/hr Prl:%u Gld:%u Slv:%u Ebn:%u Azr:%u Rby:%u Amb:%u V.Time: %d ", |
|
expIntoLVL, expForLVL, expTillLVL, lmtIntoLVL, lmtTillLVL, (int)m_AshitaCore->GetDataManager()->GetPlayer()->GetMeritPoints(), xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal), |
|
crTotal, m_crKill, returnProjectedCRUORperHour(m_crTotal), m_prl, m_gld, m_slv, m_ebn, m_azr, m_rby, m_amb, m_vTime); |
|
} |
|
else |
|
{ |
|
sprintf_s(TextObjectBuffer, MAX_PATH, " %s/%s(%s) %s/10,000(%s)[%i] XP:%s(%u) %.1fk/hr ", expIntoLVL, expForLVL, expTillLVL, |
|
lmtIntoLVL, lmtTillLVL, (int)m_AshitaCore->GetDataManager()->GetPlayer()->GetMeritPoints(), xpTotal, m_xpKill, returnProjectedEXPperHour(m_xpTotal)); |
|
} |
|
} |
|
|
|
// double check the size of the text |
|
if (m_ExpObjSize.cy == 0) |
|
{ |
|
int window_y = m_AshitaCore->GetConfigurationManager()->get_int32("boot_config", "window_y", 600); |
|
m_ExpObj->GetTextSize(&m_ExpObjSize); |
|
m_ExpObj->SetPositionX(15.0f); |
|
m_ExpObj->SetPositionY((float)(window_y - m_ExpObjSize.cy)); |
|
} |
|
|
|
// set the object information |
|
m_ExpObj->SetText(TextObjectBuffer); |
|
m_ExpObj->SetVisibility(true); |
|
} |
|
#pragma endregion |
|
#pragma region returnProjectedEXPperHour |
|
float WatchEXP::returnProjectedEXPperHour(unsigned int expIntoLevel) |
|
{ |
|
float changeInTime = (float(time(nullptr) - m_BaseTimeEXP)); |
|
float changeInTimeHR = ((changeInTime / 60) / 60); |
|
|
|
if (expIntoLevel == 0) |
|
{ |
|
m_BaseTimeEXP = time(nullptr); |
|
} |
|
|
|
// just in case we don't do a divide by zero |
|
if (changeInTime == 0.0f) |
|
{ |
|
return 0; |
|
} |
|
|
|
return ((((float)expIntoLevel) / changeInTimeHR) / 1000); |
|
} |
|
#pragma endregion |
|
#pragma region returnProjectedCRUORperHour |
|
float WatchEXP::returnProjectedCRUORperHour(unsigned int cruorLVL) |
|
{ |
|
float changeInTime = (float(time(nullptr) - m_BaseTimeCR)); |
|
float changeInTimeHR = ((changeInTime / 60) / 60); |
|
|
|
if (cruorLVL == 0) |
|
{ |
|
m_BaseTimeCR = time(nullptr); |
|
} |
|
|
|
// just in case we don't do a divide by zero |
|
if (changeInTime == 0.0f) |
|
{ |
|
return 0; |
|
} |
|
|
|
return ((((float)cruorLVL) / changeInTimeHR) / 1000); |
|
} |
|
#pragma endregion |
|
#pragma region isInAbyssea |
|
bool WatchEXP::isInAbyssea(int zoneID) |
|
{ |
|
// look for it |
|
for (auto& x : AbysseaZoneIDs) |
|
{ |
|
// Yes! |
|
if (x == zoneID) |
|
return true; |
|
} |
|
|
|
m_prl = 0, m_gld = 0, m_amb = 0, m_slv = 0, m_azr = 0, m_ebn = 0, m_rby = 0, m_vTime = 0; |
|
|
|
return false; |
|
} |
|
#pragma endregion |
|
#pragma region isInDynamis |
|
bool WatchEXP::isInDynamis(int zoneID) |
|
{ |
|
// look for it |
|
for (auto& x : DynamisZoneIDs) |
|
{ |
|
// Yes! |
|
if (x == zoneID) |
|
return true; |
|
} |
|
|
|
m_Dyna_Crm = 'X', m_Dyna_Azr = 'X', m_Dyna_Alab = 'X', m_Dyna_Amb = 'X', m_Dyna_Obs = 'X'; |
|
// Nope |
|
return false; |
|
} |
|
#pragma endregion |
|
#pragma region doAbysseaZoneTimings |
|
void WatchEXP::doAbysseaZoneTimings() |
|
{ |
|
// check to see if we are in Abyssea |
|
m_IsInAbyssea = isInAbyssea(m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0)); |
|
|
|
if (m_IsInAbyssea && (time(nullptr) - m_AbyTimeStart) > 60) |
|
{ |
|
m_AbyTimeStart = time(nullptr); |
|
if (m_vTime != 0) |
|
{ |
|
m_vTime -= 1; |
|
} |
|
} |
|
} |
|
#pragma endregion |
|
#pragma region doDynamisZoneTimings |
|
void WatchEXP::doDynamisZoneTimings() |
|
{ |
|
// check to see if we are in Abyssea |
|
m_IsInDynamis = isInDynamis(m_AshitaCore->GetDataManager()->GetParty()->GetMemberZone(0)); |
|
|
|
doDynamisKItemCheck(); |
|
|
|
if (m_IsInDynamis && (time(nullptr) - m_DynTimeStart) > 60) |
|
{ |
|
m_DynTimeStart = time(nullptr); |
|
if (m_DynaTime != 0) |
|
{ |
|
m_DynaTime -= 1; |
|
} |
|
} |
|
} |
|
#pragma endregion |
|
#pragma region doDynamisKItemCheck |
|
void WatchEXP::doDynamisKItemCheck() |
|
{ |
|
//Checks for Crimson Granule of Time |
|
|
|
if (m_AshitaCore->GetDataManager()->GetPlayer()->HasKeyItem(1545)) |
|
{ |
|
m_Dyna_Crm = 'O'; |
|
} |
|
//Checks for Azure Granule of Time |
|
if (m_AshitaCore->GetDataManager()->GetPlayer()->HasKeyItem(1546)) |
|
{ |
|
m_Dyna_Azr = 'O'; |
|
} |
|
//Checks for Amber Granule of Time |
|
if (m_AshitaCore->GetDataManager()->GetPlayer()->HasKeyItem(1547)) |
|
{ |
|
m_Dyna_Amb = 'O'; |
|
} |
|
//Checks for Alabaster Granule of Time |
|
if (m_AshitaCore->GetDataManager()->GetPlayer()->HasKeyItem(1548)) |
|
{ |
|
m_Dyna_Alab = 'O'; |
|
} |
|
//Checks for Obsidian Granule of Time |
|
if (m_AshitaCore->GetDataManager()->GetPlayer()->HasKeyItem(1549)) |
|
{ |
|
m_Dyna_Obs = 'O'; |
|
} |
|
} |
|
#pragma endregion |
|
#pragma region makeComma |
|
void WatchEXP::makeComma(int n, char *p, int count) |
|
{ |
|
int d; |
|
// Get least significant digit |
|
d = n % 10; |
|
// Convert to ascii character and store |
|
*p++ = d + '0'; |
|
// Remove least significant digit |
|
// Test for finished |
|
if (n /= 10) |
|
{ |
|
// Not finished, increase digit count, |
|
// test for comma position |
|
count++; |
|
if (count >= 3) |
|
{ |
|
// Add the comma and reset the count |
|
*p++ = ','; |
|
count = 0; |
|
} |
|
// Call this procedure to work on |
|
// remaining part of number |
|
makeComma(n, p, count); |
|
} |
|
return; |
|
} |
|
#pragma endregion |
|
|
|
#pragma region convertFromHex |
|
int WatchEXP::convertFromHex(std::string hex) |
|
{ |
|
int value = 0; |
|
int a = 0; |
|
int b = hex.length() - 1; |
|
|
|
for (; b >= 0; a++, b--) |
|
{ |
|
if (hex[b] >= '0' && hex[b] <= '9') |
|
{ |
|
value += (hex[b] - '0') * (1 << (a * 4)); |
|
} |
|
else |
|
{ |
|
switch (hex[b]) |
|
{ |
|
case 'A': |
|
|
|
case 'a': |
|
value += 10 * (1 << (a * 4)); |
|
break; |
|
|
|
case 'B': |
|
|
|
case 'b': |
|
value += 11 * (1 << (a * 4)); |
|
break; |
|
|
|
case 'C': |
|
|
|
case 'c': |
|
value += 12 * (1 << (a * 4)); |
|
break; |
|
|
|
case 'D': |
|
|
|
case 'd': |
|
value += 13 * (1 << (a * 4)); |
|
break; |
|
|
|
case 'E': |
|
|
|
case 'e': |
|
value += 14 * (1 << (a * 4)); |
|
break; |
|
|
|
case 'F': |
|
|
|
case 'f': |
|
value += 15 * (1 << (a * 4)); |
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
} |
|
} |
|
return value; |
|
} |
|
#pragma endregion |
|
#pragma region hextodec |
|
void WatchEXP::hextodec(std::string hex, std::vector<unsigned char>& rgb) |
|
{ |
|
std::string redString, greenString, blueString; |
|
|
|
if (hex.compare(0, 1, "#") == 0) |
|
{ |
|
//If the prefix # was attached to hex, use the following code |
|
redString = hex.substr(1, 2); |
|
greenString = hex.substr(3, 2); |
|
blueString = hex.substr(5, 2); |
|
} |
|
else if (hex.compare(0, 2, "0x") == 0) |
|
{ |
|
//If the prefix 0x was attached to hex, use the following code |
|
redString = hex.substr(2, 2); |
|
greenString = hex.substr(4, 2); |
|
blueString = hex.substr(6, 2); |
|
} |
|
else |
|
{ |
|
//If there is no prefix attached to hex, use this code |
|
redString = hex.substr(0, 2); |
|
greenString = hex.substr(2, 2); |
|
blueString = hex.substr(4, 2); |
|
} |
|
|
|
unsigned char red = (unsigned char)(convertFromHex(redString)); |
|
unsigned char green = (unsigned char)(convertFromHex(greenString)); |
|
unsigned char blue = (unsigned char)(convertFromHex(blueString)); |
|
|
|
rgb[0] = red; |
|
rgb[1] = green; |
|
rgb[2] = blue; |
|
} |
|
#pragma endregion |
|
#pragma region convertTrans |
|
void WatchEXP::convertTrans(unsigned char& trans) |
|
{ |
|
float temp1, temp2; |
|
|
|
temp1 = (float)trans; |
|
|
|
temp2 = temp1 * (float)2.55; |
|
|
|
if (temp2 > 255) |
|
{ |
|
trans = (unsigned char)255; |
|
} |
|
else |
|
{ |
|
trans = (unsigned char)temp2; |
|
} |
|
} |
|
#pragma endregion |
|
#pragma region checkResetTime |
|
void WatchEXP::checkResetTime() |
|
{ |
|
if (time(nullptr) - m_resetTime > 60) |
|
{ |
|
if (m_xpTest != m_xpTotal) |
|
{ |
|
m_xpTest = m_xpTotal; |
|
m_resetTime = time(nullptr); |
|
} |
|
else if ((m_xpTest == m_xpTotal) && (m_autoreset)) |
|
{ |
|
if (((time(nullptr) - m_resetTime) / 60) >= m_reset_min) |
|
{ |
|
m_resetTime = time(nullptr); |
|
|
|
m_crTotal = 0, m_xpTotal = 0, m_xpKill = 0, m_crKill = 0; |
|
} |
|
} |
|
} |
|
} |
|
#pragma endregion |
|
#pragma region ScrubChat |
|
std::string WatchEXP::ScrubChat(const char* chat_line) |
|
{ |
|
//strings to hold the chat data through the various scrubbing stages |
|
std::string chat_raw; |
|
std::string clean_chat_pass1; |
|
std::string clean_chat_pass2; |
|
std::string clean_chat_pass3; |
|
std::string clean_chat_final; |
|
|
|
char szClean[1024]; |
|
|
|
//regex expressions for parsing the raw chat until it's clean |
|
std::regex parse1("\\x1E\\x05|\\x1E(\\x03|\\x02|\\x01)|\\x7F\\x31|\\x1F(\\x79|\\x7F|\\x7B|\\W)"); |
|
std::regex parse2("[[:cntrl:]]|\\W\\W"); |
|
std::regex time_stamp("\\x1E\\x03((\\[\\d+(:|/)\\d+(:|/)\\d+(\\]| [AMP]+\\]))|\\[\\d+(:|/)\\d+(:|/)\\d+ - \\d+:\\d+:\\d+(\\]| [AMP]+\\]))\\x1E\\x01\\s+"); |
|
std::regex multi_space("\\s+"); |
|
|
|
memset(szClean, 0, 1024); |
|
|
|
//Cleans up any auto translate data so it can be properly parsed |
|
m_AshitaCore->GetChatManager()->ParseAutoTranslate(chat_line, szClean, 1024, false); |
|
|
|
chat_raw = chat_line; |
|
|
|
//Removes TimeStamp data from beginning of line |
|
std::regex_replace(std::back_inserter(clean_chat_pass1), chat_raw.begin(), chat_raw.end(), time_stamp, ""); |
|
|
|
//Removes some control characters from the beginning and end of the string that print as garbage |
|
std::regex_replace(std::back_inserter(clean_chat_pass2), clean_chat_pass1.begin(), clean_chat_pass1.end(), parse1, ""); |
|
|
|
//Removes any remaining control characters and replaces them with spaces |
|
std::regex_replace(std::back_inserter(clean_chat_pass3), clean_chat_pass2.begin(), clean_chat_pass2.end(), parse2, " "); |
|
|
|
//Changes any multi space areas to single spaces |
|
std::regex_replace(std::back_inserter(clean_chat_final), clean_chat_pass3.begin(), clean_chat_pass3.end(), multi_space, " "); |
|
|
|
return clean_chat_final; |
|
} |
|
#pragma endregion |