From d5098a56e0d50af6b687874b5e7374b3d43055d9 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 20 Jun 2015 19:44:00 -0700 Subject: [PATCH] Timers and some more loading stuff --- common/clientversions.h | 22 ++++++++ common/ruletypes.h | 1 + world/client.cpp | 8 ++- zone/aa.cpp | 122 ++++++++++++++++++++++++++++++++-------- zone/aa.h | 7 +++ zone/aa_ability.h | 1 - zone/aa_rank.h | 2 +- zone/aa_rank_prereqs.h | 33 ----------- zone/client.cpp | 10 +--- zone/client.h | 3 +- zone/client_packet.cpp | 10 +++- zone/command.cpp | 34 +++++++++++ zone/command.h | 4 +- zone/entity.cpp | 8 +++ zone/entity.h | 2 +- zone/mob.h | 2 + zone/npc.cpp | 1 - zone/spells.cpp | 8 +-- 18 files changed, 199 insertions(+), 79 deletions(-) delete mode 100644 zone/aa_rank_prereqs.h diff --git a/common/clientversions.h b/common/clientversions.h index 675429eab..4e575f8f4 100644 --- a/common/clientversions.h +++ b/common/clientversions.h @@ -150,4 +150,26 @@ static ClientVersion ClientVersionFromBit(uint32 clientVersionBit) } } +static uint32 ExpansionFromClientVersion(ClientVersion clientVersion) +{ + switch(clientVersion) + { + case ClientVersion::Unknown: + case ClientVersion::Client62: + case ClientVersion::Titanium: + return 0x000007FFU; + case ClientVersion::SoF: + return 0x00007FFFU; + case ClientVersion::SoD: + return 0x0000FFFFU; + case ClientVersion::UF: + return 0x0001FFFFU; + case ClientVersion::RoF: + case ClientVersion::RoF2: + return 0x000FFFFFU; + default: + return 0; + } +} + #endif /* CLIENTVERSIONS_H */ diff --git a/common/ruletypes.h b/common/ruletypes.h index 4c9430998..8dffc82e5 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -184,6 +184,7 @@ RULE_INT(World, MinGMAntiHackStatus, 1) //Minimum GM status to check against Ant RULE_INT(World, SoFStartZoneID, -1) //Sets the Starting Zone for SoF Clients separate from Titanium Clients (-1 is disabled) RULE_INT(World, TitaniumStartZoneID, -1) //Sets the Starting Zone for Titanium Clients (-1 is disabled). Replaces the old method. RULE_INT(World, ExpansionSettings, 16383) // Sets the expansion settings for the server, This is sent on login to world and affects client expansion settings. Defaults to all expansions enabled up to TSS. +RULE_BOOL(World, UseClientBasedExpansionSettings, true) // if true it will overrule World, ExpansionSettings and set someone's expansion based on the client they're using RULE_INT(World, PVPSettings, 0) // Sets the PVP settings for the server, 1 = Rallos Zek RuleSet, 2 = Tallon/Vallon Zek Ruleset, 4 = Sullon Zek Ruleset, 6 = Discord Ruleset, anything above 6 is the Discord Ruleset without the no-drop restrictions removed. TODO: Edit IsAttackAllowed in Zone to accomodate for these rules. RULE_BOOL (World, IsGMPetitionWindowEnabled, false) RULE_INT (World, FVNoDropFlag, 0) // Sets the Firiona Vie settings on the client. If set to 2, the flag will be set for GMs only, allowing trading of no-drop items. diff --git a/world/client.cpp b/world/client.cpp index 26a69222b..2c476902a 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -152,7 +152,13 @@ void Client::SendEnterWorld(std::string name) void Client::SendExpansionInfo() { auto outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct)); ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer; - eis->Expansions = (RuleI(World, ExpansionSettings)); + if(RuleB(World, UseClientBasedExpansionSettings)) { + eis->Expansions = ExpansionFromClientVersion(eqs->GetClientVersion()); + //eis->Expansions = ExpansionFromClientVersion(this->GetCLE. + } else { + eis->Expansions = (RuleI(World, ExpansionSettings)); + } + QueuePacket(outapp); safe_delete(outapp); } diff --git a/zone/aa.cpp b/zone/aa.cpp index 741a15aff..0c31034c7 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -872,8 +872,8 @@ void Client::SendAlternateAdvancementRank(int aa_id, int level) { } for(auto &prereq : rank->prereqs) { - outapp->WriteSInt32(prereq.aa_id); - outapp->WriteSInt32(prereq.points); + outapp->WriteSInt32(prereq.first); + outapp->WriteSInt32(prereq.second); } QueuePacket(outapp); @@ -948,6 +948,41 @@ void Client::SendAlternateAdvancementTimers() { safe_delete(outapp); } +void Client::ResetAlternateAdvancementTimer(int ability) { + AA::Rank *rank = zone->GetAlternateAdvancementRank(casting_spell_aa_id); + if(rank) { + SendAlternateAdvancementTimer(rank->spell_type, 0, time(0)); + p_timers.Clear(&database, rank->spell_type + pTimerAAStart); + } +} + +void Client::ResetAlternateAdvancementTimers() { + EQApplicationPacket* outapp = new EQApplicationPacket(OP_AAAction, sizeof(UseAA_Struct)); + UseAA_Struct* uaaout = (UseAA_Struct*)outapp->pBuffer; + + PTimerList::iterator c, e; + c = p_timers.begin(); + e = p_timers.end(); + std::vector r_timers; + for(; c != e; ++c) { + PersistentTimer *cur = c->second; + if(cur->GetType() < pTimerAAStart || cur->GetType() > pTimerAAEnd) + continue; + //send timer + uaaout->begin = 0; + uaaout->end = static_cast(time(nullptr)); + uaaout->ability = cur->GetType() - pTimerAAStart; + r_timers.push_back(cur->GetType()); + QueuePacket(outapp); + } + + for(auto &i : r_timers) { + p_timers.Clear(&database, i); + } + + safe_delete(outapp); +} + void Client::PurchaseAlternateAdvancementRank(int rank_id) { AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id); if(!rank) { @@ -1212,13 +1247,13 @@ void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) { bool ZoneDatabase::LoadAlternateAdvancement(Client *c) { c->ClearAAs(); std::string query = StringFormat( - "SELECT " - "aa_id, " - "aa_value, " - "charges " - "FROM " - "`character_alternate_abilities` " - "WHERE `id` = %u ORDER BY `slot`", c->CharacterID()); + "SELECT " + "aa_id, " + "aa_value, " + "charges " + "FROM " + "`character_alternate_abilities` " + "WHERE `id` = %u", c->CharacterID()); MySQLRequestResult results = database.QueryDatabase(query); int i = 0; @@ -1227,11 +1262,25 @@ bool ZoneDatabase::LoadAlternateAdvancement(Client *c) { uint32 value = atoi(row[1]); uint32 charges = atoi(row[2]); - c->GetPP().aa_array[i].AA = aa; - c->GetPP().aa_array[i].value = value; - c->GetPP().aa_array[i].charges = charges; - c->SetAA(aa, value, charges); - i++; + auto rank = zone->GetAlternateAdvancementRank(aa); + if(!rank) { + continue; + } + + auto ability = rank->base_ability; + if(!ability) { + continue; + } + + rank = ability->GetRankByPointsSpent(value); + + if(c->CanUseAlternateAdvancementRank(rank)) { + c->GetPP().aa_array[i].AA = aa; + c->GetPP().aa_array[i].value = value; + c->GetPP().aa_array[i].charges = charges; + c->SetAA(aa, value, charges); + i++; + } } return true; @@ -1359,8 +1408,14 @@ bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) { } } - if(!(RuleI(World, ExpansionSettings) & (1 << rank->expansion))) { - return false; + if(IsClient()) { + if(!(CastToClient()->GetPP().expansions & (1 << rank->expansion))) { + return false; + } + } else { + if(!(RuleI(World, ExpansionSettings) & (1 << rank->expansion))) { + return false; + } } auto race = GetArrayRace(GetBaseRace()); @@ -1427,11 +1482,11 @@ bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price) //check prereqs for(auto &prereq : rank->prereqs) { - AA::Ability *prereq_ability = zone->GetAlternateAdvancementAbility(prereq.aa_id); + AA::Ability *prereq_ability = zone->GetAlternateAdvancementAbility(prereq.first); if(prereq_ability) { auto ranks = GetAA(prereq_ability->first_rank_id); - if(ranks < prereq.points) { + if(ranks < prereq.second) { return false; } } @@ -1473,6 +1528,24 @@ void Zone::LoadAlternateAdvancement() { if(current->prev) { current->total_cost = current->cost + current->prev->total_cost; + + //check prereqs here + for(auto &prev_prereq : current->prev->prereqs) { + // //if prev has an aa we dont have set + // // then set it here too + // //if prev has an aa we have and the count is different + // // then set to whichever is highest + // + auto iter = current->prereqs.find(prev_prereq.first); + if(iter == current->prereqs.end()) { + //not found + current->prereqs[prev_prereq.first] = prev_prereq.second; + } else { + //they already have it too! + auto points = std::max(iter->second, prev_prereq.second); + current->prereqs[iter->first] = points; + } + } } else { current->prev_id = -1; @@ -1593,14 +1666,17 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map 0) { AA::Rank *rank = ranks[rank_id].get(); - rank->prereqs.push_back(prereq); + rank->prereqs[aa_id] = points; } } } else { @@ -1650,4 +1726,4 @@ void Mob::GrantAlternateAdvancementAbility(int aa_id, int points) { c->SendAlternateAdvancementStats(); c->CalcBonuses(); } -} \ No newline at end of file +} diff --git a/zone/aa.h b/zone/aa.h index 76df0f388..280f56d53 100644 --- a/zone/aa.h +++ b/zone/aa.h @@ -1536,4 +1536,11 @@ public: uint32 owner_id; }; +enum AATimers +{ + aaTimerRampage, + aaTimerWarcry, + aaTimerMax +}; + #endif diff --git a/zone/aa_ability.h b/zone/aa_ability.h index 4a2d41f3e..0d6a240c4 100644 --- a/zone/aa_ability.h +++ b/zone/aa_ability.h @@ -24,7 +24,6 @@ #include #include #include "aa_rank_effects.h" -#include "aa_rank_prereqs.h" #include "aa_rank.h" class Mob; diff --git a/zone/aa_rank.h b/zone/aa_rank.h index 977a07680..c328e4ebb 100644 --- a/zone/aa_rank.h +++ b/zone/aa_rank.h @@ -48,7 +48,7 @@ public: int total_cost; Ability *base_ability; std::vector effects; - std::vector prereqs; + std::map prereqs; }; } diff --git a/zone/aa_rank_prereqs.h b/zone/aa_rank_prereqs.h deleted file mode 100644 index b1620be6c..000000000 --- a/zone/aa_rank_prereqs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef EQEMU_ZONE_AA_RANK_PREREQS_H -#define EQEMU_ZONE_AA_RANK_PREREQS_H - -namespace AA -{ - -struct RankPrereq -{ - int aa_id; - int points; -}; - -} - -#endif diff --git a/zone/client.cpp b/zone/client.cpp index 0ce7292ef..ae0ceedff 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -524,7 +524,6 @@ void Client::ReportConnectingState() { } bool Client::SaveAA() { - std::string dquery; std::string iquery; int spentpoints = 0; int i = 0; @@ -546,10 +545,10 @@ bool Client::SaveAA() { spentpoints += r->total_cost; if(i == 0) { - iquery = StringFormat("INSERT INTO `character_alternate_abilities` (id, slot, aa_id, aa_value, charges)" - " VALUES (%u, %u, %u, %u, %u)", character_id, i, ability->first_rank_id, rank.second.first, rank.second.second); + iquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)" + " VALUES (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second); } else { - iquery += StringFormat(", (%u, %u, %u, %u, %u)", character_id, i, ability->first_rank_id, rank.second.first, rank.second.second); + iquery += StringFormat(", (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second); } i++; } @@ -557,9 +556,6 @@ bool Client::SaveAA() { m_pp.aapoints_spent = spentpoints + m_epp.expended_aa; - dquery = StringFormat("DELETE FROM `character_alternate_abilities` WHERE id=%u", character_id); - database.QueryDatabase(dquery); - if(iquery.length() > 0) { database.QueryDatabase(iquery); } diff --git a/zone/client.h b/zone/client.h index 034ff83b4..07d42a313 100644 --- a/zone/client.h +++ b/zone/client.h @@ -45,7 +45,6 @@ struct Item_Struct; #include "../common/item_struct.h" #include "../common/clientversions.h" -#include "aa.h" #include "common.h" #include "merc.h" #include "mob.h" @@ -768,6 +767,8 @@ public: void SendAlternateAdvancementPoints(); void SendAlternateAdvancementTimer(int ability, int begin, int end); void SendAlternateAdvancementTimers(); + void ResetAlternateAdvancementTimer(int ability); + void ResetAlternateAdvancementTimers(); void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAlternateAdvancementStats(); } void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAlternateAdvancementStats(); } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index d01bcf109..8f4b55004 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1440,6 +1440,13 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; } if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; } + if(RuleB(World, UseClientBasedExpansionSettings)) { + m_pp.expansions = ExpansionFromClientVersion(GetClientVersion()); + } + else { + m_pp.expansions = RuleI(World, ExpansionSettings); + } + if(!database.LoadAlternateAdvancement(this)) { Log.Out(Logs::General, Logs::Error, "Error loading AA points for %s", GetName()); } @@ -1566,9 +1573,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Update LFP in case any (or all) of our group disbanded while we were zoning. */ if (IsLFP()) { UpdateLFP(); } - /* Get Expansions from variables table and ship via PP */ - m_pp.expansions = RuleI(World, ExpansionSettings); - p_timers.SetCharID(CharacterID()); if (!p_timers.Load(&database)) { Log.Out(Logs::General, Logs::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID()); diff --git a/zone/command.cpp b/zone/command.cpp index ab2b4ad78..59f4bfa8a 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -320,6 +320,7 @@ int command_init(void) { command_add("raidloot", "LEADER|GROUPLEADER|SELECTED|ALL - Sets your raid loot settings if you have permission to do so.", 0, command_raidloot) || command_add("randomfeatures", "- Temporarily randomizes the Facial Features of your target", 80, command_randomfeatures) || command_add("refreshgroup", "- Refreshes Group.", 0, command_refreshgroup) || + command_add("reloadaa", "Reloads AA data", 200, command_reloadaa) || command_add("reloadallrules", "Executes a reload of all rules.", 80, command_reloadallrules) || command_add("reloademote", "Reloads NPC Emotes", 80, command_reloademote) || command_add("reloadlevelmods", nullptr,255, command_reloadlevelmods) || @@ -333,6 +334,7 @@ int command_init(void) { command_add("reloadzps", nullptr,0, command_reloadzps) || command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) || command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", 200, command_resetaa) || + command_add("resetaa_timer", "Command to reset AA cooldown timers.", 200, command_resetaa_timer) || command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) || command_add("rules", "(subcommand) - Manage server rules", 250, command_rules) || command_add("save", "- Force your player or player corpse target to be saved to the database", 50, command_save) || @@ -10580,3 +10582,35 @@ void command_mysqltest(Client *c, const Seperator *sep) } Log.Out(Logs::General, Logs::Debug, "MySQL Test... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC); } + +void command_resetaa_timer(Client *c, const Seperator *sep) { + Client *target = nullptr; + if(!c->GetTarget() || !c->GetTarget()->IsClient()) { + target = c; + } else { + target = c->GetTarget()->CastToClient(); + } + + if(sep->IsNumber(1)) + { + int timer_id = atoi(sep->arg[1]); + c->Message(0, "Reset of timer %i for %s", timer_id, c->GetName()); + c->ResetAlternateAdvancementTimer(timer_id); + } + else if(!strcasecmp(sep->arg[1], "all")) + { + c->Message(0, "Reset all timers for %s", c->GetName()); + c->ResetAlternateAdvancementTimers(); + } + else + { + c->Message(0, "usage: #resetaa_timer [all | timer_id]"); + } +} + +void command_reloadaa(Client *c, const Seperator *sep) { + c->Message(0, "Reloading Alternate Advancement Data..."); + zone->LoadAlternateAdvancement(); + c->Message(0, "Alternate Advancement Data Reloaded"); + entity_list.SendAlternateAdvancementStats(); +} \ No newline at end of file diff --git a/zone/command.h b/zone/command.h index f44362ea7..795f75919 100644 --- a/zone/command.h +++ b/zone/command.h @@ -323,7 +323,9 @@ void command_tune(Client *c, const Seperator *sep); void command_logtest(Client *c, const Seperator *sep); void command_mysqltest(Client *c, const Seperator *sep); void command_logs(Client *c, const Seperator *sep); - +void command_resetaa_timer(Client *c, const Seperator *sep); +void command_reloadaa(Client *c, const Seperator *sep); + #ifdef EQPROFILE void command_profiledump(Client *c, const Seperator *sep); void command_profilereset(Client *c, const Seperator *sep); diff --git a/zone/entity.cpp b/zone/entity.cpp index 5033c52fe..8749b102c 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4704,3 +4704,11 @@ void EntityList::StopMobAI() mob.second->AI_ShutDown(); } } + +void EntityList::SendAlternateAdvancementStats() { + for(auto &c : client_list) { + c.second->SendAlternateAdvancementTable(); + c.second->SendAlternateAdvancementStats(); + c.second->SendAlternateAdvancementPoints(); + } +} diff --git a/zone/entity.h b/zone/entity.h index 446c5d505..1adf23783 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -398,7 +398,6 @@ public: void SaveAllClientsTaskState(); void ReloadAllClientsTaskState(int TaskID=0); - uint16 CreateGroundObject(uint32 itemid, const glm::vec4& position, uint32 decay_time = 300000); uint16 CreateGroundObjectFromModel(const char *model, const glm::vec4& position, uint8 type = 0x00, uint32 decay_time = 0); uint16 CreateDoor(const char *model, const glm::vec4& position, uint8 type = 0, uint16 size = 100); @@ -429,6 +428,7 @@ public: uint16 GetFreeID(); void RefreshAutoXTargets(Client *c); void RefreshClientXTargets(Client *c); + void SendAlternateAdvancementStats(); protected: friend class Zone; diff --git a/zone/mob.h b/zone/mob.h index 1c3d7ab15..8352d764e 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -24,6 +24,7 @@ #include "pathing.h" #include "position.h" #include "aa_ability.h" +#include "aa.h" #include #include #include @@ -1327,6 +1328,7 @@ protected: bool destructibleobject; std::unordered_map> aa_ranks; + Timer aa_timers[aaTimerMax]; private: void _StopSong(); //this is not what you think it is diff --git a/zone/npc.cpp b/zone/npc.cpp index d4a33b6d0..2d0c1f13b 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -31,7 +31,6 @@ #include "../common/linked_list.h" #include "../common/servertalk.h" -#include "aa.h" #include "client.h" #include "entity.h" #include "npc.h" diff --git a/zone/spells.cpp b/zone/spells.cpp index ec872d1c9..4f492c343 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -818,12 +818,8 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid) } if(casting_spell_aa_id && IsClient()) { //Rest AA Timer on failed cast - AA::Rank *rank = zone->GetAlternateAdvancementRank(casting_spell_aa_id); - if(rank) { - CastToClient()->Message_StringID(MT_SpellFailure, ABILITY_FAILED); - CastToClient()->SendAlternateAdvancementTimer(rank->spell_type, 0, 0x7fffffff); - CastToClient()->GetPTimers().Clear(&database, rank->spell_type + pTimerAAStart); - } + CastToClient()->Message_StringID(MT_SpellFailure, ABILITY_FAILED); + CastToClient()->ResetAlternateAdvancementTimer(casting_spell_aa_id); } ZeroCastingVars(); // resets all the state keeping stuff