From 250d0cc9036475d1622893c27321f649b443c69e Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 8 Jun 2015 20:06:14 -0700 Subject: [PATCH] More aa work, it actually loads yay --- common/eq_packet_structs.h | 3 +- common/patches/uf.cpp | 71 +++++++- common/patches/uf_structs.h | 3 +- zone/CMakeLists.txt | 1 + zone/aa.cpp | 315 +++++++++++++++++++++++++++++++++--- zone/aa_ability.cpp | 69 ++++++++ zone/aa_ability.h | 15 +- zone/aa_rank.h | 12 +- zone/client.h | 6 +- zone/client_packet.cpp | 7 +- zone/zone.h | 5 + 11 files changed, 469 insertions(+), 38 deletions(-) create mode 100644 zone/aa_ability.cpp diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index da965f4ba..d2d9ae8b3 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -4220,7 +4220,7 @@ struct UseAA_Struct { }; //new AA stuff - +//reference only struct AARankInfo_Struct { uint32 id; @@ -4244,6 +4244,7 @@ struct AARankInfo_Struct int32 expansion; int32 category; uint8 expendable; + uint8 grant_only; uint32 total_effects; uint32 total_prereqs; }; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index deedcec5f..bbe0c0f0d 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1804,11 +1804,11 @@ namespace UF // OUT(unknown00224[48]); //NOTE: new client supports 300 AAs, our internal rep/PP //only supports 240.. - for (r = 0; r < MAX_PP_AA_ARRAY; r++) { - OUT(aa_array[r].AA); - OUT(aa_array[r].value); - OUT(aa_array[r].charges); - } + //for (r = 0; r < MAX_PP_AA_ARRAY; r++) { + // OUT(aa_array[r].AA); + // OUT(aa_array[r].value); + // OUT(aa_array[r].charges); + //} // OUT(unknown02220[4]); OUT(mana); OUT(cur_hp); @@ -2145,13 +2145,66 @@ namespace UF ENCODE(OP_SendAATable) { +#if 1 + EQApplicationPacket *inapp = *p; + *p = nullptr; + AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer; + + EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability)); + structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer; + + inapp->SetReadPosition(sizeof(AARankInfo_Struct)); + outapp->SetWritePosition(sizeof(structs::SendAA_Struct)); + + eq->id = emu->id; + eq->unknown004 = 1; + eq->id = emu->id; + eq->hotkey_sid = emu->upper_hotkey_sid; + eq->hotkey_sid2 = emu->lower_hotkey_sid; + eq->desc_sid = emu->desc_sid; + eq->title_sid = emu->title_sid; + eq->class_type = emu->level_req; + eq->cost = emu->cost; + eq->seq = emu->seq; + eq->current_level = emu->current_level; + eq->type = emu->type; + eq->spellid = emu->spell; + eq->spell_type = emu->spell_type; + eq->spell_refresh = emu->spell_refresh; + eq->classes = emu->classes; + eq->max_level = emu->max_level; + eq->last_id = emu->prev_id; + eq->next_id = emu->next_id; + eq->cost2 = emu->total_cost; + eq->grant_only = emu->grant_only > 0 ? true : false; + eq->expendable_charges = emu->expendable ? 1 : 0; + eq->aa_expansion = emu->expansion; + eq->special_category = emu->category; + eq->total_abilities = emu->total_effects; + + for(auto i = 0; i < eq->total_abilities; ++i) { + eq->abilities[i].skill_id = inapp->ReadUInt32(); + eq->abilities[i].base1 = inapp->ReadUInt32(); + eq->abilities[i].base2 = inapp->ReadUInt32(); + eq->abilities[i].slot = inapp->ReadUInt32(); + } + + if(emu->total_prereqs > 0) { + eq->prereq_skill = -(int)inapp->ReadUInt32(); + eq->prereq_minpoints = inapp->ReadUInt32(); + } + + Log.Out(Logs::General, Logs::Status, "%s", DumpPacketToString(outapp).c_str()); + dest->FastQueuePacket(&outapp); + delete inapp; +#else ENCODE_LENGTH_ATLEAST(SendAA_Struct); SETUP_VAR_ENCODE(SendAA_Struct); ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); // Check clientver field to verify this AA should be sent for SoF // clientver 1 is for all clients and 6 is for Underfoot - if (emu->clientver <= 6) + if(emu->clientver <= 6) { OUT(id); eq->unknown004 = 1; @@ -2174,7 +2227,7 @@ namespace UF OUT(spell_type); OUT(spell_refresh); OUT(classes); - OUT(berserker); + //OUT(berserker); //eq->max_level = emu->sof_max_level; OUT(max_level); OUT(last_id); @@ -2185,7 +2238,7 @@ namespace UF eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number OUT(total_abilities); unsigned int r; - for (r = 0; r < emu->total_abilities; r++) { + for(r = 0; r < emu->total_abilities; r++) { OUT(abilities[r].skill_id); OUT(abilities[r].base1); OUT(abilities[r].base2); @@ -2193,7 +2246,9 @@ namespace UF } } + Log.Out(Logs::General, Logs::Status, "%s", DumpPacketToString(__packet).c_str()); FINISH_ENCODE(); +#endif } ENCODE(OP_SendCharInfo) diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index c943c6ea5..36d6dea74 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -3886,8 +3886,7 @@ struct SendAA_Struct { /*0049*/ uint32 spellid; /*0053*/ uint32 spell_type; /*0057*/ uint32 spell_refresh; -/*0061*/ uint16 classes; -/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability +/*0061*/ uint32 classes; /*0065*/ uint32 max_level; /*0069*/ uint32 last_id; /*0073*/ uint32 next_id; diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index a68945155..ba9aa8620 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(zone_sources aa.cpp + aa_ability.cpp aggro.cpp attack.cpp beacon.cpp diff --git a/zone/aa.cpp b/zone/aa.cpp index edca1ebdb..88e2a2e56 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1097,22 +1097,24 @@ void Client::SendAATimers() { } void Client::SendAATable() { + Log.Out(Logs::General, Logs::Status, "SendAATable()"); EQApplicationPacket* outapp = new EQApplicationPacket(OP_RespondAA, sizeof(AATable_Struct)); AATable_Struct* aa2 = (AATable_Struct *)outapp->pBuffer; - aa2->aa_spent = GetAAPointsSpent(); - - uint32 i; - for(i=0;i < MAX_PP_AA_ARRAY;i++){ - aa2->aa_list[i].AA = aa[i]->value ? aa[i]->AA : 0; // bit of a hack to prevent expendables punching a hole - aa2->aa_list[i].value = aa[i]->value; - aa2->aa_list[i].charges = aa[i]->charges; - } + //aa2->aa_spent = GetAAPointsSpent(); + // + //uint32 i; + //for(i=0;i < MAX_PP_AA_ARRAY;i++){ + // aa2->aa_list[i].AA = aa[i]->value ? aa[i]->AA : 0; // bit of a hack to prevent expendables punching a hole + // aa2->aa_list[i].value = aa[i]->value; + // aa2->aa_list[i].charges = aa[i]->charges; + //} QueuePacket(outapp); safe_delete(outapp); } void Client::SendPreviousAA(uint32 id, int seq){ + Log.Out(Logs::General, Logs::Status, "SendPreviousAA(%u, %i)", id, seq); uint32 value=0; SendAA_Struct* saa2 = nullptr; if(id==0) @@ -1148,11 +1150,13 @@ void Client::SendPreviousAA(uint32 id, int seq){ } database.FillAAEffects(saa); + Log.Out(Logs::General, Logs::Status, "%s", DumpPacketToString(outapp).c_str()); QueuePacket(outapp); safe_delete(outapp); } void Client::SendAA(uint32 id, int seq) { + Log.Out(Logs::General, Logs::Status, "SendAA(%u, %i)", id, seq); uint32 value=0; SendAA_Struct* saa2 = nullptr; @@ -1368,6 +1372,7 @@ void Client::SendAA(uint32 id, int seq) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAATable); outapp->size=size; outapp->pBuffer=(uchar*)saa; + if(id==0 && value && (orig_val < saa->max_level)) //send previous AA only on zone in SendPreviousAA(id, seq); @@ -1377,10 +1382,13 @@ void Client::SendAA(uint32 id, int seq) { } void Client::SendAAList(){ -// int total = zone->GetTotalAAs(); -// for(int i=0;i < total;i++){ -// SendAA(0,i); -// } + Log.Out(Logs::General, Logs::Status, "SendAAList()"); + int total = zone->GetTotalAAs(); + + total = total > 2 ? 2 : total; + for(int i=0;i < total;i++){ + SendAA(0,i); + } } uint32 Client::GetAA(uint32 aa_id) const { @@ -2080,39 +2088,300 @@ Mob *AA_SwarmPetInfo::GetOwner() return entity_list.GetMobID(owner_id); } +void Client::SendAlternateAdvancementList() { + for(auto &aa : zone->aa_abilities) { + SendAlternateAdvancement(aa.first, true); + } +} + //New AA +void Client::SendAlternateAdvancement(int aa_id, bool first_login) { + if(!zone) + return; + + AA::Ability *ability = zone->GetAlternateAdvancementAbility(aa_id); + + if(!ability) + return; + + if(!(ability->classes & (1 << GetClass()))) { + return; + } + + if(ability->account_time_required) { + if((Timer::GetTimeSeconds() - account_creation) < ability->account_time_required) + { + return; + } + } + + // Hide Quest/Progression AAs unless player has been granted the first level using $client->IncrementAA(skill_id). + if(ability->category == 1 || ability->category == 2) { + //if(GetAA(saa2->id) == 0) + // return; + + if(ability->expansion > 0) { + AA::Ability *qaa = zone->GetAlternateAdvancementAbility(aa_id + 1); + //if(qaa && qaa->expansion == ability->expansion && GetAA(aa_id) > 0) { + // return; + //} + } + } + + // Passive and Active Shroud AAs + // For now we skip them + if(ability->category == 3 || ability->category == 4) { + return; + } + + // Check for racial/Drakkin blood line AAs + if(ability->category == 8) + { + uint32 client_race = GetBaseRace(); + + // Drakkin Bloodlines + if(ability->expansion > 522) + { + if(client_race != 522) + return; + + int heritage = this->GetDrakkinHeritage() + 523; // 523 = Drakkin Race(522) + Bloodline + + if(heritage != ability->expansion) + return; + } + else if(client_race != ability->expansion) + { + return; + } + } + + //Send first rank + AA::Rank *rank = ability->first; + if(!rank) + return; + + //Should move this to another function + int size = sizeof(AARankInfo_Struct)+(sizeof(AARankEffect_Struct)* rank->effects.size()) + (sizeof(AARankPrereq_Struct)* rank->prereqs.size()); + EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, size); + AARankInfo_Struct *aai = (AARankInfo_Struct*)outapp->pBuffer; + + aai->id = rank->id; + aai->upper_hotkey_sid = rank->upper_hotkey_sid; + aai->lower_hotkey_sid = rank->lower_hotkey_sid; + aai->title_sid = rank->title_sid; + aai->desc_sid = rank->desc_sid; + aai->level_req = rank->level_req; + aai->cost = rank->cost; + aai->seq = aa_id; + aai->current_level = 1; + aai->type = ability->type; + aai->spell = rank->spell; + aai->spell_type = rank->spell_type; + aai->spell_refresh = rank->recast_time; + aai->classes = ability->classes; + aai->max_level = ability->GetMaxLevel(); + aai->prev_id = rank->prev_id; + aai->next_id = rank->next_id; + aai->total_cost = rank->total_cost; + aai->expansion = ability->expansion; + aai->category = ability->category; + aai->expendable = ability->expendable; + aai->grant_only = ability->grant_only; + aai->total_effects = rank->effects.size(); + aai->total_prereqs = rank->prereqs.size(); + + outapp->SetWritePosition(sizeof(AARankInfo_Struct)); + for(auto effect : rank->effects) { + outapp->WriteSInt32(effect.second.effect_id); + outapp->WriteSInt32(effect.second.base1); + outapp->WriteSInt32(effect.second.base2); + outapp->WriteSInt32(effect.first); + } + + for(auto prereq : rank->prereqs) { + outapp->WriteSInt32(prereq.aa_id); + outapp->WriteSInt32(prereq.points); + } + + //if first_login then also send current rank if not maxed + + QueuePacket(outapp); + safe_delete(outapp); + + // + //if(size == 0) + // return; + // + //uchar* buffer = new uchar[size]; + //SendAA_Struct* saa = (SendAA_Struct*)buffer; + //memcpy(saa, saa2, size); + // + //if(saa->spellid == 0) + // saa->spellid = 0xFFFFFFFF; + // + //value = GetAA(saa->id); + //uint32 orig_val = value; + // + //if(value && saa->id){ + // + // if(value < saa->max_level){ + // saa->id += value; + // saa->next_id = saa->id + 1; + // value++; + // } + // + // else if(aa_stack && saa->sof_next_id){ + // saa->id += value - 1; + // saa->next_id = saa->sof_next_id; + // + // //Prevent removal of previous AA from window if next AA belongs to a higher client version. + // SendAA_Struct* saa_next = nullptr; + // saa_next = zone->FindAA(saa->sof_next_id); + // + // // this check should work as long as we continue to just add the clients and just increase + // // each number .... + // if(saa_next && static_cast(GetClientVersion()) < saa_next->clientver - 1) { + // saa->next_id = 0xFFFFFFFF; + // } + // } + // + // else{ + // saa->id += value - 1; + // saa->next_id = 0xFFFFFFFF; + // } + // + // uint32 current_level_mod = 0; + // if(aa_stack) + // current_level_mod = saa->sof_current_level; + // + // saa->last_id = saa->id - 1; + // saa->current_level = value + (current_level_mod); + // saa->cost = saa2->cost + (saa2->cost_inc*(value - 1)); + // saa->cost2 = 0; + // for(uint32 i = 0; i < value; i++) { + // saa->cost2 += saa2->cost + (saa2->cost_inc * i); + // } + // saa->class_type = saa2->class_type + (saa2->level_inc*(value - 1)); + //} + // + //if(aa_stack){ + // + // if(saa->sof_current_level >= 1 && value == 0) + // saa->current_level = saa->sof_current_level + 1; + // + // saa->max_level = saa->sof_max_level; + //} + // + //database.FillAAEffects(saa); + // + //if(value > 0) + //{ + // // AA_Action stores the base ID + // const AA_DBAction *caa = &AA_Actions[saa->id - value + 1][value - 1]; + // + // if(caa && caa->reuse_time > 0) + // saa->spell_refresh = CalcAAReuseTimer(caa); + //} + // + ////You can now use the level_inc field in the altadv_vars table to accomplish this, though still needed + ////for special cases like LOH/HT due to inability to implement correct stacking of AA's that use hotkeys. + //std::map::iterator RequiredLevel = AARequiredLevelAndCost.find(saa->id); + // + //if(RequiredLevel != AARequiredLevelAndCost.end()) + //{ + // saa->class_type = RequiredLevel->second.Level; + // saa->cost = RequiredLevel->second.Cost; + //} + // + // + //EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAATable); + //outapp->size = size; + //outapp->pBuffer = (uchar*)saa; + //if(id == 0 && value && (orig_val < saa->max_level)) //send previous AA only on zone in + // SendPreviousAA(id, seq); + // + //QueuePacket(outapp); + //safe_delete(outapp); + ////will outapp delete the buffer for us even though it didnt make it? --- Yes, it should +} + void Zone::LoadAlternateAdvancement() { Log.Out(Logs::General, Logs::Status, "Loading Alternate Advancement Data..."); - if(!database.LoadAlternateAdvancementAbilities(zone->aa_abilities, - zone->aa_ranks)) + if(!database.LoadAlternateAdvancementAbilities(aa_abilities, + aa_ranks)) { - zone->aa_abilities.clear(); - zone->aa_ranks.clear(); + aa_abilities.clear(); + aa_ranks.clear(); Log.Out(Logs::General, Logs::Status, "Failed to load Alternate Advancement Data"); return; } + Log.Out(Logs::General, Logs::Status, "Processing Alternate Advancement Data..."); + for(const auto &ability : aa_abilities) { + ability.second->first = GetAlternateAdvancementRank(ability.second->first_rank_id); + + //process these ranks + AA::Rank *current = ability.second->first; + while(current) { + current->prev = GetAlternateAdvancementRank(current->prev_id); + current->next = GetAlternateAdvancementRank(current->next_id); + current->base_ability = ability.second.get(); + + if(current->prev) { + current->total_cost = current->cost + current->prev->total_cost; + } else { + current->total_cost = current->cost; + } + + current = current->next; + } + + ability.second->GetMaxLevel(true); + } + Log.Out(Logs::General, Logs::Status, "Loaded Alternate Advancement Data"); } +AA::Ability *Zone::GetAlternateAdvancementAbility(int id) { + auto iter = aa_abilities.find(id); + if(iter != aa_abilities.end()) { + return iter->second.get(); + } + + return nullptr; +} + +AA::Rank *Zone::GetAlternateAdvancementRank(int rank_id) { + auto iter = aa_ranks.find(rank_id); + if(iter != aa_ranks.end()) { + return iter->second.get(); + } + + return nullptr; +} + bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map> &abilities, std::unordered_map> &ranks) { Log.Out(Logs::General, Logs::Status, "Loading Alternate Advancement Abilities..."); abilities.clear(); - std::string query = "SELECT id, name, expansion, category, classes, expendable, first_rank_id FROM aa_ability"; + std::string query = "SELECT id, name, expansion, category, classes, type, expendable, account_time_required, grant_only, first_rank_id FROM aa_ability"; auto results = QueryDatabase(query); if(results.Success()) { for(auto row = results.begin(); row != results.end(); ++row) { AA::Ability *ability = new AA::Ability; int id = atoi(row[0]); - ability->name = row[1]; ability->expansion = atoi(row[2]); ability->category = atoi(row[3]); ability->classes = atoi(row[4]); - ability->expendable = atoi(row[5]) != 0 ? true : false; - ability->first_rank_id = atoi(row[6]); + ability->type = atoi(row[5]); + ability->expendable = atoi(row[6]) != 0 ? true : false; + ability->account_time_required = atoul(row[7]); + ability->grant_only = atoi(row[8]) != 0 ? true : false; + ability->first_rank_id = atoi(row[9]); + ability->first = nullptr; abilities[id] = std::unique_ptr(ability); } @@ -2132,6 +2401,7 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_mapid = id; rank->upper_hotkey_sid = atoi(row[1]); rank->lower_hotkey_sid = atoi(row[2]); rank->title_sid = atoi(row[3]); @@ -2143,6 +2413,10 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_maprecast_time = atoi(row[9]); rank->prev_id = atoi(row[10]); rank->next_id = atoi(row[11]); + rank->base_ability = nullptr; + rank->total_cost = 0; + rank->next = nullptr; + rank->prev = nullptr; ranks[id] = std::unique_ptr(rank); } @@ -2204,4 +2478,3 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_mapnext) { + current = current->next; + } + + return current; +} + +AA::Rank *AA::Ability::GetRankByPointsSpent(int current_level) { + if(!first) + return nullptr; + + if(current_level == 0) { + return GetMaxRank(); + } + + int i = 1; + Rank *current = first; + while(current->next) { + if(1 == current_level) { + break; + } + + i++; + current = current->next; + } + + return current; +} + +int AA::Ability::GetMaxLevel(bool force_calc) { + if(!force_calc) + return max_level; + + max_level = 0; + Rank *current = first; + while(current) { + max_level++; + current = current->next; + } + + return max_level; +} \ No newline at end of file diff --git a/zone/aa_ability.h b/zone/aa_ability.h index bb9148689..b2098c408 100644 --- a/zone/aa_ability.h +++ b/zone/aa_ability.h @@ -30,14 +30,27 @@ namespace AA { -struct Ability +class Ability { +public: + Ability() { } + ~Ability() { } + + Rank *GetMaxRank(); + Rank *GetRankByPointsSpent(int current_level); + int GetMaxLevel(bool force_calc = false); + std::string name; int expansion; int category; int classes; + uint32 account_time_required; + bool grant_only; + int type; bool expendable; int first_rank_id; + int max_level; + Rank *first; }; } diff --git a/zone/aa_rank.h b/zone/aa_rank.h index ec1cc4115..43b6ef635 100644 --- a/zone/aa_rank.h +++ b/zone/aa_rank.h @@ -22,8 +22,14 @@ namespace AA { -struct Rank +class Ability; +class Rank { +public: + Rank() { } + ~Rank() { } + + int id; int upper_hotkey_sid; int lower_hotkey_sid; int title_sid; @@ -34,7 +40,11 @@ struct Rank int spell_type; int recast_time; int prev_id; + Rank *prev; int next_id; + Rank *next; + int total_cost; + Ability *base_ability; std::unordered_map effects; std::vector prereqs; }; diff --git a/zone/client.h b/zone/client.h index de093990c..7bc4aac1e 100644 --- a/zone/client.h +++ b/zone/client.h @@ -759,7 +759,11 @@ public: inline PTimerList &GetPTimers() { return(p_timers); } - //AA Methods + //New AA Methods + void SendAlternateAdvancement(int aa_id, bool first_login = false); + void SendAlternateAdvancementList(); + + //old AA Methods void SendAAList(); void ResetAA(); void SendClearAA(); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index df8ef8f12..bfe96fdb3 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1091,8 +1091,10 @@ void Client::Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app) void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app) { - Log.Out(Logs::General, Logs::Error, "SendAAList()"); - SendAAList(); + //SendAAList(); + + SendAlternateAdvancementList(); + return; } @@ -1153,7 +1155,6 @@ void Client::Handle_Connect_OP_TGB(const EQApplicationPacket *app) void Client::Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app) { - Log.Out(Logs::General, Logs::Error, "SendAATable()"); SendAATable(); } diff --git a/zone/zone.h b/zone/zone.h index 274a1a021..fbe1b48d1 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -116,6 +116,8 @@ public: //new AA void LoadAlternateAdvancement(); + AA::Ability *GetAlternateAdvancementAbility(int id); + AA::Rank *GetAlternateAdvancementRank(int rank_id); //old AA void LoadAAs(); @@ -319,10 +321,13 @@ private: int totalBS; ZoneSpellsBlocked *blocked_spells; +public: //new AA std::unordered_map> aa_abilities; std::unordered_map> aa_ranks; +private: + //old AA int totalAAs; SendAA_Struct **aas; //array of AA structs