int32 Client::CalcBaseHP() { if(GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { int stats = GetSTA(); if(stats > 255) { stats = (stats - 255) / 2; stats += 255; } base_hp = 5; auto base_data = database.GetBaseData(GetLevel(), GetClass()); if(base_data) { base_hp += base_data->base_hp + (base_data->hp_factor * stats); base_hp += (GetHeroicSTA() * 10); } } else { uint32 Post255; uint32 lm=GetClassLevelFactor(); if((GetSTA()-255)/2 > 0) Post255 = (GetSTA()-255)/2; else Post255 = 0; base_hp = (5)+(GetLevel()*lm/10) + (((GetSTA()-Post255)*GetLevel()*lm/3000)) + ((Post255*GetLevel())*lm/6000); } return base_hp; }
int32 Client::CalcBaseEndurance() { int32 base_end = 0; if(GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { double heroic_stats = (GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4.0f; double stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4.0f; if(stats > 201.0f) { stats = 1.25f * (stats - 201.0f) + 352.5f; } else if(stats > 100.0f) { stats = 2.5f * (stats - 100.0f) + 100.0f; } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if(base_data) { base_end = base_data->base_end + (heroic_stats * 10.0f) + (base_data->endurance_factor * static_cast<int>(stats)); } } else { int Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI(); int LevelBase = GetLevel() * 15; int at_most_800 = Stats; if(at_most_800 > 800) at_most_800 = 800; int Bonus400to800 = 0; int HalfBonus400to800 = 0; int Bonus800plus = 0; int HalfBonus800plus = 0; int BonusUpto800 = int( at_most_800 / 4 ) ; if(Stats > 400) { Bonus400to800 = int( (at_most_800 - 400) / 4 ); HalfBonus400to800 = int( std::max( ( at_most_800 - 400 ), 0 ) / 8 ); if(Stats > 800) { Bonus800plus = int( (Stats - 800) / 8 ) * 2; HalfBonus800plus = int( (Stats - 800) / 16 ); } } int bonus_sum = BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus; base_end = LevelBase; //take all of the sums from above, then multiply by level*0.075 base_end += ( bonus_sum * 3 * GetLevel() ) / 40; } return base_end; }
int32 Client::CalcBaseHP() { if(GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { float SoDPost255; uint16 NormalSTA = GetSTA(); if(((NormalSTA - 255) / 2) > 0) SoDPost255 = ((NormalSTA - 255) / 2); else SoDPost255 = 0; int hp_factor = GetClassHPFactor(); if (level < 41) { base_hp = (5 + (GetLevel() * hp_factor / 12) + ((NormalSTA - SoDPost255) * GetLevel() * hp_factor / 3600)); } else if (level < 81) { base_hp = (5 + (40 * hp_factor / 12) + ((GetLevel() - 40) * hp_factor / 6) + ((NormalSTA - SoDPost255) * hp_factor / 90) + ((NormalSTA - SoDPost255) * (GetLevel() - 40) * hp_factor / 1800)); } else { base_hp = (5 + (80 * hp_factor / 8) + ((GetLevel() - 80) * hp_factor / 10) + ((NormalSTA - SoDPost255) * hp_factor / 90) + ((NormalSTA - SoDPost255) * hp_factor / 45)); } base_hp += (GetHeroicSTA() * 10); } else { uint16 Post255; uint16 lm=GetClassLevelFactor(); if((GetSTA()-255)/2 > 0) Post255 = (GetSTA()-255)/2; else Post255 = 0; base_hp = (5)+(GetLevel()*lm/10) + (((GetSTA()-Post255)*GetLevel()*lm/3000)) + ((Post255*GetLevel())*lm/6000); } return base_hp; }
void Client::SendGuildURL() { if(GetClientVersion() < EQClientSoF) return; if(IsInAGuild()) { EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildUpdateURLAndChannel, sizeof(GuildUpdateURLAndChannel_Struct)); GuildUpdateURLAndChannel_Struct *guuacs = (GuildUpdateURLAndChannel_Struct*) outapp->pBuffer; if(guild_mgr.GetGuildURL(GuildID(), guuacs->Text)) { guuacs->Action = 0; FastQueuePacket(&outapp); } else safe_delete(outapp); } }
int32 Client::GetMaxStat() const { if ((RuleI(Character, StatCap)) > 0) { return (RuleI(Character, StatCap)); } int level = GetLevel(); int32 base = 0; if (level < 61) { base = 255; } else if (GetClientVersion() >= ClientVersion::SoF) { base = 255 + 5 * (level - 60); } else if (level < 71) { base = 255 + 5 * (level - 60); } else { base = 330; } return (base); }
int32 Client::CalcBaseMana() { int WisInt = 0; int MindLesserFactor, MindFactor; int32 max_m = 0; int wisint_mana = 0; int base_mana = 0; int ConvertedWisInt = 0; switch(GetCasterClass()) { case 'I': WisInt = GetINT(); if (GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { if (WisInt > 100) { ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); if (WisInt > 201) { ConvertedWisInt -= ((WisInt - 201) * 5 / 4); } } else { ConvertedWisInt = WisInt; } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if(base_data) { max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicINT() * 10); } } else { if((( WisInt - 199 ) / 2) > 0) MindLesserFactor = ( WisInt - 199 ) / 2; else MindLesserFactor = 0; MindFactor = WisInt - MindLesserFactor; if(WisInt > 100) max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40); else max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100); } break; case 'W': WisInt = GetWIS(); if (GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { if (WisInt > 100) { ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); if (WisInt > 201) { ConvertedWisInt -= ((WisInt - 201) * 5 / 4); } } else { ConvertedWisInt = WisInt; } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if(base_data) { max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicWIS() * 10); } } else { if((( WisInt - 199 ) / 2) > 0) MindLesserFactor = ( WisInt - 199 ) / 2; else MindLesserFactor = 0; MindFactor = WisInt - MindLesserFactor; if(WisInt > 100) max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40); else max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100); } break; case 'N': { max_m = 0; break; } default: { LogFile->write(EQEMuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass()); max_m = 0; break; } } #if EQDEBUG >= 11 LogFile->write(EQEMuLog::Debug, "Client::CalcBaseMana() called for %s - returning %d", GetName(), max_m); #endif return max_m; }
bool CHexarcSession::Connect (CString *retsError) // Connect // // Connect to the server (if not already connected) { // Already connected? if (m_Session.IsConnected()) return true; // Need host and root URL if (m_sHost.IsBlank() || m_sRootURL.IsBlank()) { *retsError = ERR_NO_SERVER_DEFINED; return false; } // Connect to host EInetsErrors iError = m_Session.Connect(m_sHost, m_sPort); if (iError != inetsOK) { switch (iError) { case inetsDNSError: *retsError = strPatternSubst(ERR_DNS_ERROR, GetHostspec()); kernelDebugLogMessage(*retsError); return false; case inetsCannotConnect: *retsError = strPatternSubst(ERR_CONNECT_ERROR, GetHostspec()); kernelDebugLogMessage(*retsError); return false; default: *retsError = strPatternSubst(ERR_INTERNAL, GetHostspec()); kernelDebugLogMessage(*retsError); return false; } } // Compose a connect payload CJSONValue Payload(CJSONValue::typeObject); Payload.InsertHandoff(FIELD_CLIENT_ID, CJSONValue(m_sClientID)); Payload.InsertHandoff(FIELD_CLIENT_VERSION, CJSONValue(GetClientVersion())); Payload.InsertHandoff(FIELD_PROTOCOL_VERSION, CJSONValue(TRANS_SERVICE_VERSION)); if (!m_sUsername.IsBlank()) Payload.InsertHandoff(FIELD_USERNAME, CJSONValue(m_sUsername)); // Now issue the connect command CHTTPMessage Request; InitRequest(METHOD_POST, FUNC_CONNECT_CLIENT, &Request); Request.SetBody(new CJSONMessage(Payload)); // Send the request and wait for response CHTTPMessage Response; if (iError = m_Session.Send(Request, &Response)) { m_Session.Disconnect(); *retsError = strPatternSubst(ERR_REQUEST_FAILED, GetHostspec()); kernelDebugLogMessage(*retsError); return false; } // If we got a 301 redirect then we try the whole thing again if (Response.GetStatusCode() == 301) { m_Session.Disconnect(); // LATER: Set up the new host and recurse // LATER: Keep track of recursion count, in case of ping-pong redirects *retsError = CONSTLIT("LATER: Redirect"); kernelDebugLogMessage(*retsError); return false; } // If we get an error, return else if (Response.GetStatusCode() != 200) { m_Session.Disconnect(); *retsError = strPatternSubst(ERR_FROM_SERVER, GetHostspec(), Response.GetStatusMsg()); kernelDebugLogMessage(*retsError); return false; } // Get the JSON response CJSONValue ResponseData; if (!GetJSONResponse(Response, &ResponseData, retsError)) { m_Session.Disconnect(); *retsError = strPatternSubst(ERR_INVALID_JSON, GetHostspec(), *retsError); return false; } // If this is an error, then return it if (CHexarc::IsError(ResponseData, NULL, retsError)) { m_Session.Disconnect(); kernelDebugLogMessage(*retsError); return false; } // LATER: Process return value (challenge) // Done return true; }
bool Client::UseDiscipline(uint32 spell_id, uint32 target) { // Dont let client waste a reuse timer if they can't use the disc if (IsStunned() || IsFeared() || IsMezzed() || IsAmnesiad() || IsPet()) { return(false); } //EQMac can assume we have all discs if we are here. if(GetClientVersion() > EQClientMac) { //make sure we have the spell... int r; for(r = 0; r < MAX_PP_DISCIPLINES; r++) { if(m_pp.disciplines.values[r] == spell_id) break; } if(r == MAX_PP_DISCIPLINES) return(false); //not found. } //Check the disc timer pTimerType DiscTimer = pTimerDisciplineReuseStart + spells[spell_id].EndurTimerIndex; if(!p_timers.Expired(&database, DiscTimer)) { /*char val1[20]={0};*/ //unused /*char val2[20]={0};*/ //unused uint32 remain = p_timers.GetRemainingTime(DiscTimer); //Message_StringID(CC_Default, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2)); Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60)); return(false); } //make sure we can use it.. if(!IsValidSpell(spell_id)) { Message(13, "This tome contains invalid knowledge."); return(false); } //can we use the spell? const SPDat_Spell_Struct &spell = spells[spell_id]; uint8 level_to_use = spell.classes[GetClass() - 1]; if(level_to_use == 255) { Message(13, "Your class cannot learn from this tome."); //should summon them a new one... return(false); } if(level_to_use > GetLevel()) { Message_StringID(CC_Red, DISC_LEVEL_USE_ERROR); //should summon them a new one... return(false); } if(GetEndurance() > spell.EndurCost) { SetEndurance(GetEndurance() - spell.EndurCost); TryTriggerOnValueAmount(false, false, true); } else { Message(11, "You are too fatigued to use this skill right now."); return(false); } if(spell.recast_time > 0) { uint32 reduced_recast = spell.recast_time / 1000; reduced_recast -= CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id); if(reduced_recast < 0) reduced_recast = 0; CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); if(spells[spell_id].EndurTimerIndex < MAX_DISCIPLINE_TIMERS) { EQApplicationPacket *outapp = new EQApplicationPacket(OP_DisciplineTimer, sizeof(DisciplineTimer_Struct)); DisciplineTimer_Struct *dts = (DisciplineTimer_Struct *)outapp->pBuffer; dts->TimerID = spells[spell_id].EndurTimerIndex; dts->Duration = reduced_recast; QueuePacket(outapp); safe_delete(outapp); } } else { CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); } return(true); }
uint32 Client::CalcCurrentWeight() { const Item_Struct* TempItem = 0; ItemInst* ins; uint32 Total = 0; int x; for (x = EmuConstants::EQUIPMENT_BEGIN; x <= MainCursor; x++) { // include cursor or not? TempItem = 0; ins = GetInv().GetItem(x); if (ins) { TempItem = ins->GetItem(); } if (TempItem) { Total += TempItem->Weight; } } for (x = EmuConstants::GENERAL_BAGS_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) { // include cursor bags or not? int TmpWeight = 0; TempItem = 0; ins = GetInv().GetItem(x); if (ins) { TempItem = ins->GetItem(); } if (TempItem) { TmpWeight = TempItem->Weight; } if (TmpWeight > 0) { // this code indicates that weight redux bags can only be in the first general inventory slot to be effective... // is this correct? or can we scan for the highest weight redux and use that? (need client verifications) int bagslot = MainGeneral1; int reduction = 0; for (int m = EmuConstants::GENERAL_BAGS_BEGIN + 10; m <= EmuConstants::GENERAL_BAGS_END; m += 10) { // include cursor bags or not? if (x >= m) { bagslot += 1; } } ItemInst* baginst = GetInv().GetItem(bagslot); if (baginst && baginst->GetItem() && baginst->IsType(ItemClassContainer)) { reduction = baginst->GetItem()->BagWR; } if (reduction > 0) { TmpWeight -= TmpWeight * reduction / 100; } Total += TmpWeight; } } //TODO: coin weight reduction (from purses, etc), since client already calculates it /* From the Wiki http://www.eqemulator.net/wiki/wikka.php?wakka=EQEmuDBSchemaitems under bagwr (thanks Trevius): Interestingly, you can also have bags that reduce coin weight. However, in order to set bags to reduce coin weight, you MUST set the Item ID somewhere between 17201 and 17230. This is hard coded into the client. The client is set to have certain coin weight reduction on a per Item ID basis within this range. The best way to create an new item to reduce coin weight is to examine existing bags in this range. Search for the words "coin purse" with the #finditem command in game and the Bag WR setting on those bags is the amount they will reduce coin weight. It is easiest to overwrite one of those bags if you wish to create one with the same weight reduction amount for coins. You can use other Item IDs in this range for setting coin weight reduction, but by using an existing item, at least you will know the amount the client will reduce it by before you create it. This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item. It is very odd. */ // SoD+ client has no weight for coin if (EQLimits::CoinHasWeight(GetClientVersion())) { Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4; } float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat; if (Packrat > 0) { Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same % } //without casting to float & back to uint32, this didn't work right return Total; }
int32 Client::CalcBaseEndurance() { int32 base_end = 0; int32 base_endurance = 0; int32 ConvertedStats = 0; int32 sta_end = 0; int Stats = 0; if(GetClientVersion() >= EQClientSoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { int HeroicStats = 0; Stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4); HeroicStats = ((GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4); if (Stats > 100) { ConvertedStats = (((Stats - 100) * 5 / 2) + 100); if (Stats > 201) { ConvertedStats -= ((Stats - 201) * 5 / 4); } } else { ConvertedStats = Stats; } if (GetLevel() < 41) { sta_end = (GetLevel() * 75 * ConvertedStats / 1000); base_endurance = (GetLevel() * 15); } else if (GetLevel() < 81) { sta_end = ((3 * ConvertedStats) + ((GetLevel() - 40) * 15 * ConvertedStats / 100)); base_endurance = (600 + ((GetLevel() - 40) * 30)); } else { sta_end = (9 * ConvertedStats); base_endurance = (1800 + ((GetLevel() - 80) * 18)); } base_end = (base_endurance + sta_end + (HeroicStats * 10)); } else { Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI(); int LevelBase = GetLevel() * 15; int at_most_800 = Stats; if(at_most_800 > 800) at_most_800 = 800; int Bonus400to800 = 0; int HalfBonus400to800 = 0; int Bonus800plus = 0; int HalfBonus800plus = 0; int BonusUpto800 = int( at_most_800 / 4 ) ; if(Stats > 400) { Bonus400to800 = int( (at_most_800 - 400) / 4 ); HalfBonus400to800 = int( max( ( at_most_800 - 400 ), 0 ) / 8 ); if(Stats > 800) { Bonus800plus = int( (Stats - 800) / 8 ) * 2; HalfBonus800plus = int( (Stats - 800) / 16 ); } } int bonus_sum = BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus; base_end = LevelBase; //take all of the sums from above, then multiply by level*0.075 base_end += ( bonus_sum * 3 * GetLevel() ) / 40; } return base_end; }
uint32 Client::CalcCurrentWeight() { const Item_Struct* TempItem = 0; ItemInst* ins; uint32 Total = 0; int x; for(x = 0; x <= 30; x++) { TempItem = 0; ins = GetInv().GetItem(x); if (ins) TempItem = ins->GetItem(); if (TempItem) Total += TempItem->Weight; } for (x = 251; x < 331; x++) { int TmpWeight = 0; TempItem = 0; ins = GetInv().GetItem(x); if (ins) TempItem = ins->GetItem(); if (TempItem) TmpWeight = TempItem->Weight; if (TmpWeight > 0) { int bagslot = 22; int reduction = 0; for (int m = 261; m < 331; m += 10) { if (x >= m) bagslot += 1; } ItemInst* baginst = GetInv().GetItem(bagslot); if (baginst && baginst->GetItem() && baginst->IsType(ItemClassContainer)) reduction = baginst->GetItem()->BagWR; if (reduction > 0) TmpWeight -= TmpWeight*reduction/100; Total += TmpWeight; } } //TODO: coin weight reduction (from purses, etc), since client already calculates it /*From the Wiki http://www.eqemulator.net/wiki/wikka.php?wakka=EQEmuDBSchemaitems under bagwr (thanks Trevius): Interestingly, you can also have bags that reduce coin weight. However, in order to set bags to reduce coin weight, you MUST set the Item ID somewhere between 17201 and 17230. This is hard coded into the client. The client is set to have certain coin weight reduction on a per Item ID basis within this range. The best way to create an new item to reduce coin weight is to examine existing bags in this range. Search for the words "coin purse" with the #finditem command in game and the Bag WR setting on those bags is the amount they will reduce coin weight. It is easiest to overwrite one of those bags if you wish to create one with the same weight reduction amount for coins. You can use other Item IDs in this range for setting coin weight reduction, but by using an existing item, at least you will know the amount the client will reduce it by before you create it. This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item. It is very odd. */ // SoD client has no weight for coin if (GetClientVersion() < EQClientSoD) { Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4; } float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat; if (Packrat > 0) Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same % //without casting to float & back to uint32, this didn't work right return Total; }