More aa work, it actually loads yay

This commit is contained in:
KimLS 2015-06-08 20:06:14 -07:00
parent 361c93b689
commit 250d0cc903
11 changed files with 469 additions and 38 deletions

View File

@ -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;
};

View File

@ -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)

View File

@ -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;

View File

@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(zone_sources
aa.cpp
aa_ability.cpp
aggro.cpp
attack.cpp
beacon.cpp

View File

@ -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<int>(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<uint32, AALevelCost_Struct>::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<int, std::unique_ptr<AA::Ability>> &abilities,
std::unordered_map<int, std::unique_ptr<AA::Rank>> &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<AA::Ability>(ability);
}
@ -2132,6 +2401,7 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map<int, std
for(auto row = results.begin(); row != results.end(); ++row) {
AA::Rank *rank = new AA::Rank;
int id = atoi(row[0]);
rank->id = 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_map<int, std
rank->recast_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<AA::Rank>(rank);
}
@ -2204,4 +2478,3 @@ bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map<int, std
return true;
}

69
zone/aa_ability.cpp Normal file
View File

@ -0,0 +1,69 @@
/* 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
*/
#include "../common/global_define.h"
#include "../common/types.h"
#include "aa_ability.h"
AA::Rank *AA::Ability::GetMaxRank() {
if(!first)
return nullptr;
Rank *current = first;
while(current->next) {
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;
}

View File

@ -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;
};
}

View File

@ -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<int, RankEffect> effects;
std::vector<RankPrereq> prereqs;
};

View File

@ -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();

View File

@ -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();
}

View File

@ -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<int, std::unique_ptr<AA::Ability>> aa_abilities;
std::unordered_map<int, std::unique_ptr<AA::Rank>> aa_ranks;
private:
//old AA
int totalAAs;
SendAA_Struct **aas; //array of AA structs