From 8c9b8525864c1c7ffce1691ef03205d2a0ea86fb Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 19 Sep 2017 02:01:06 -0400 Subject: [PATCH] Fix food/drink to match live --- common/features.h | 5 +++ common/ruletypes.h | 2 +- zone/bonuses.cpp | 11 ++++++ zone/client.cpp | 81 +++++++++++++++++------------------------ zone/client.h | 1 - zone/client_packet.cpp | 4 ++ zone/client_process.cpp | 49 +++++++++++++------------ zone/common.h | 1 + zone/spell_effects.cpp | 10 ----- 9 files changed, 82 insertions(+), 82 deletions(-) diff --git a/common/features.h b/common/features.h index 550c3fa7b..486255f28 100644 --- a/common/features.h +++ b/common/features.h @@ -276,6 +276,11 @@ enum { #define SAYLINK_ITEM_ID 0xFFFFF +// consumption timers for food/drink here instead of rules because the client +// uses these. Times in ms. +#define CONSUMPTION_TIMER 46000 +#define CONSUMPTION_MNK_TIMER 92000 + /* Developer configuration diff --git a/common/ruletypes.h b/common/ruletypes.h index 529c7d239..20bdce740 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -117,7 +117,7 @@ RULE_BOOL(Character, EnableDiscoveredItems, true) // If enabled, it enables EVEN RULE_BOOL(Character, EnableXTargetting, true) // Enable Extended Targetting Window, for users with UF and later clients. RULE_BOOL(Character, EnableAggroMeter, true) // Enable Aggro Meter, for users with RoF and later clients. RULE_BOOL(Character, KeepLevelOverMax, false) // Don't delevel a character that has somehow gone over the level cap -RULE_INT(Character, FoodLossPerUpdate, 35) // How much food/water you lose per stamina update +RULE_INT(Character, FoodLossPerUpdate, 32) // How much food/water you lose per stamina update RULE_INT(Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods, 36 commonly referred to as "3.6" as well. RULE_BOOL(Character, UseSpellFileSongCap, true) // When they removed the AA that increased the cap they removed the above and just use the spell field RULE_INT(Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225. diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 098de9eb9..acf604cf1 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -120,6 +120,13 @@ void Client::CalcBonuses() if (GetMaxXTargets() != 5 + aabonuses.extra_xtargets) SetMaxXTargets(5 + aabonuses.extra_xtargets); + + // hmm maybe a better way to do this + int metabolism = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism; + int timer = GetClass() == MONK ? CONSUMPTION_MNK_TIMER : CONSUMPTION_TIMER; + timer = timer * (100 + metabolism) / 100; + if (timer != consume_food_timer.GetTimerTime()) + consume_food_timer.SetTimer(timer); } int Client::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat) @@ -2503,6 +2510,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne new_bonus->MagicWeapon = true; break; + case SE_Hunger: + new_bonus->hunger = true; + break; + case SE_IncreaseBlockChance: if (AdditiveWornBonus) new_bonus->IncreaseBlockChance += effect_value; diff --git a/zone/client.cpp b/zone/client.cpp index 7a7c57861..da95a0ad7 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -123,8 +123,7 @@ Client::Client(EQStreamInterface* ieqs) hpupdate_timer(2000), camp_timer(29000), process_timer(100), - stamina_timer(40000), - consume_food_timer(60000), + consume_food_timer(CONSUMPTION_TIMER), zoneinpacket_timer(1000), linkdead_timer(RuleI(Zone,ClientLinkdeadMS)), dead_timer(2000), @@ -8591,64 +8590,52 @@ void Client::SetConsumption(int32 in_hunger, int32 in_thirst) void Client::Consume(const EQEmu::ItemData *item, uint8 type, int16 slot, bool auto_consume) { - if(!item) { return; } + if (!item) + return; - /* - Spell Bonuses 2 digit form - 10, 20, 25 etc. (10%, 20%, 25%) - AA Bonus Ranks, 110, 125, 150 etc. (10%, 25%, 50%) - */ + int increase = item->CastTime_ * 100; + if (!auto_consume) // force feeding is half as effective + increase /= 2; - float aa_bonus = ((float) aabonuses.Metabolism - 100) / 100; - float item_bonus = (float) itembonuses.Metabolism / 100; - float spell_bonus = (float) spellbonuses.Metabolism / 100; - - float metabolism_mod = 1 + spell_bonus + item_bonus + aa_bonus; - - Log(Logs::General, Logs::Food, "Client::Consume() Metabolism bonuses spell_bonus: (%.2f) item_bonus: (%.2f) aa_bonus: (%.2f) final: (%.2f)", - spell_bonus, - item_bonus, - aa_bonus, - metabolism_mod - ); + if (increase < 0) // wasn't food? oh well + return; if (type == EQEmu::item::ItemTypeFood) { - int hunger_change = item->CastTime_ * metabolism_mod; - hunger_change = mod_food_value(item, hunger_change); + increase = mod_food_value(item, increase); - if(hunger_change < 0) - return; + if (increase < 0) + return; - m_pp.hunger_level += hunger_change; + m_pp.hunger_level += increase; - Log(Logs::General, Logs::Food, "Consuming food, points added to hunger_level: %i - current_hunger: %i", hunger_change, m_pp.hunger_level); - - DeleteItemInInventory(slot, 1, false); - - if(!auto_consume) //no message if the client consumed for us - entity_list.MessageClose_StringID(this, true, 50, 0, EATING_MESSAGE, GetName(), item->Name); - - Log(Logs::General, Logs::Food, "Eating from slot: %i", (int)slot); - - } - else { - int thirst_change = item->CastTime_ * metabolism_mod; - thirst_change = mod_drink_value(item, thirst_change); - - if(thirst_change < 0) - return; - - m_pp.thirst_level += thirst_change; + Log(Logs::General, Logs::Food, "Consuming food, points added to hunger_level: %i - current_hunger: %i", + increase, m_pp.hunger_level); DeleteItemInInventory(slot, 1, false); - Log(Logs::General, Logs::Food, "Consuming drink, points added to thirst_level: %i current_thirst: %i", thirst_change, m_pp.thirst_level); + if (!auto_consume) // no message if the client consumed for us + entity_list.MessageClose_StringID(this, true, 50, 0, EATING_MESSAGE, GetName(), item->Name); - if(!auto_consume) //no message if the client consumed for us + Log(Logs::General, Logs::Food, "Eating from slot: %i", (int)slot); + + } else { + increase = mod_drink_value(item, increase); + + if (increase < 0) + return; + + m_pp.thirst_level += increase; + + DeleteItemInInventory(slot, 1, false); + + Log(Logs::General, Logs::Food, "Consuming drink, points added to thirst_level: %i current_thirst: %i", + increase, m_pp.thirst_level); + + if (!auto_consume) // no message if the client consumed for us entity_list.MessageClose_StringID(this, true, 50, 0, DRINKING_MESSAGE, GetName(), item->Name); - Log(Logs::General, Logs::Food, "Drinking from slot: %i", (int)slot); - - } + Log(Logs::General, Logs::Food, "Drinking from slot: %i", (int)slot); + } } void Client::SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg) diff --git a/zone/client.h b/zone/client.h index b6098c6b3..051d433e4 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1458,7 +1458,6 @@ private: Timer hpupdate_timer; Timer camp_timer; Timer process_timer; - Timer stamina_timer; Timer consume_food_timer; Timer zoneinpacket_timer; Timer linkdead_timer; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 733250700..7b48b207b 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1410,6 +1410,10 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) drakkin_tattoo = m_pp.drakkin_tattoo; drakkin_details = m_pp.drakkin_details; + // we know our class now, so we might have to fix our consume timer! + if (class_ == MONK) + consume_food_timer.SetTimer(CONSUMPTION_MNK_TIMER); + /* If GM not set in DB, and does not meet min status to be GM, reset */ if (m_pp.gm && admin < minStatusToBeGM) m_pp.gm = 0; diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 5ab5db7a8..4802c24a9 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -524,10 +524,9 @@ bool Client::Process() { DoEnduranceUpkeep(); } - if (consume_food_timer.Check()) { - m_pp.hunger_level = m_pp.hunger_level - 1; - m_pp.thirst_level = m_pp.thirst_level - 1; - } + // this is independent of the tick timer + if (consume_food_timer.Check()) + DoStaminaHungerUpdate(); if (tic_timer.Check() && !dead) { CalcMaxHP(); @@ -539,7 +538,6 @@ bool Client::Process() { DoManaRegen(); DoEnduranceRegen(); BuffProcess(); - DoStaminaHungerUpdate(); if (tribute_timer.Check()) { ToggleTribute(true); //re-activate the tribute. @@ -1834,32 +1832,37 @@ void Client::DoManaRegen() { CheckManaEndUpdate(); } -void Client::DoStaminaHungerUpdate() { - if(!stamina_timer.Check()) - return; - +void Client::DoStaminaHungerUpdate() +{ auto outapp = new EQApplicationPacket(OP_Stamina, sizeof(Stamina_Struct)); - Stamina_Struct* sta = (Stamina_Struct*)outapp->pBuffer; + Stamina_Struct *sta = (Stamina_Struct *)outapp->pBuffer; - Log(Logs::General, Logs::Food, "Client::DoStaminaHungerUpdate() hunger_level: %i thirst_level: %i before loss", m_pp.hunger_level, m_pp.thirst_level); + Log(Logs::General, Logs::Food, "Client::DoStaminaHungerUpdate() hunger_level: %i thirst_level: %i before loss", + m_pp.hunger_level, m_pp.thirst_level); - if (zone->GetZoneID() != 151) { - sta->food = m_pp.hunger_level > 6000 ? 6000 : m_pp.hunger_level; - sta->water = m_pp.thirst_level > 6000 ? 6000 : m_pp.thirst_level; - } - else { + if (zone->GetZoneID() != 151 && !GetGM()) { + int loss = RuleI(Character, FoodLossPerUpdate); + if (GetHorseId() != 0) + loss *= 3; + + m_pp.hunger_level = EQEmu::Clamp(m_pp.hunger_level - loss, 0, 6000); + m_pp.thirst_level = EQEmu::Clamp(m_pp.thirst_level - loss, 0, 6000); + if (spellbonuses.hunger) { + m_pp.hunger_level = EQEmu::ClampLower(m_pp.hunger_level, 3500); + m_pp.thirst_level = EQEmu::ClampLower(m_pp.thirst_level, 3500); + } + sta->food = m_pp.hunger_level; + sta->water = m_pp.thirst_level; + } else { // No auto food/drink consumption in the Bazaar sta->food = 6000; sta->water = 6000; } - Log(Logs::General, Logs::Food, - "Client::DoStaminaHungerUpdate() Current hunger_level: %i = (%i minutes left) thirst_level: %i = (%i minutes left) - after loss", - m_pp.hunger_level, - m_pp.hunger_level, - m_pp.thirst_level, - m_pp.thirst_level - ); + Log(Logs::General, Logs::Food, + "Client::DoStaminaHungerUpdate() Current hunger_level: %i = (%i minutes left) thirst_level: %i = (%i " + "minutes left) - after loss", + m_pp.hunger_level, m_pp.hunger_level, m_pp.thirst_level, m_pp.thirst_level); FastQueuePacket(&outapp); } diff --git a/zone/common.h b/zone/common.h index 7b6382a20..bcc9ff305 100644 --- a/zone/common.h +++ b/zone/common.h @@ -550,6 +550,7 @@ struct StatBonuses { int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD int aura_slots; int trap_slots; + bool hunger; // Song of Sustenance -- min caps to 3500 }; typedef struct diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 69a5b232b..46b44fb3a 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3656,16 +3656,6 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) break; } - case SE_Hunger: { - // this procedure gets called 7 times for every once that the stamina update occurs so we add - // 1/7 of the subtraction. - // It's far from perfect, but works without any unnecessary buff checks to bog down the server. - if (IsClient()) { - CastToClient()->m_pp.hunger_level += 5; - CastToClient()->m_pp.thirst_level += 5; - } - break; - } case SE_Invisibility: case SE_InvisVsAnimals: case SE_InvisVsUndead: {