Merge conflicts abound and now are fixed

This commit is contained in:
KimLS 2015-07-02 20:12:51 -07:00
commit 214873c139
67 changed files with 24488 additions and 5020 deletions

View File

@ -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 */ #endif /* CLIENTVERSIONS_H */

View File

@ -548,4 +548,5 @@ N(OP_ZoneServerInfo),
N(OP_ZoneServerReady), N(OP_ZoneServerReady),
N(OP_ZoneSpawns), N(OP_ZoneSpawns),
N(OP_ZoneUnavail), N(OP_ZoneUnavail),
N(OP_ResetAA),
// mail and chat opcodes located in ../mail_oplist.h // mail and chat opcodes located in ../mail_oplist.h

View File

@ -4219,6 +4219,52 @@ struct UseAA_Struct {
uint32 end; uint32 end;
}; };
//new AA stuff
//reference only
struct AARankInfo_Struct
{
uint32 id;
int32 upper_hotkey_sid;
int32 lower_hotkey_sid;
int32 title_sid;
int32 desc_sid;
int32 level_req;
int32 cost;
uint32 seq;
uint32 current_level;
uint32 type;
int32 spell;
int32 spell_type;
int32 spell_refresh;
int32 classes;
int32 max_level;
int32 prev_id;
int32 next_id;
int32 total_cost;
int32 expansion;
int32 category;
uint32 charges;
uint8 grant_only;
uint32 total_effects;
uint32 total_prereqs;
};
struct AARankPrereq_Struct
{
int32 aa_id;
int32 points;
};
struct AARankEffect_Struct
{
int32 effect_id;
int32 base1;
int32 base2;
int32 slot;
};
//old AA stuff
struct AA_Ability { struct AA_Ability {
/*00*/ uint32 skill_id; /*00*/ uint32 skill_id;
/*04*/ uint32 base1; /*04*/ uint32 base1;
@ -4273,7 +4319,7 @@ struct SendAA_Struct {
struct AA_Action { struct AA_Action {
/*00*/ uint32 action; /*00*/ uint32 action;
/*04*/ uint32 ability; /*04*/ uint32 ability;
/*08*/ uint32 unknown08; /*08*/ uint32 target_id;
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };

View File

@ -2810,7 +2810,7 @@ namespace RoF
eq->aa_spent = emu->aa_spent; eq->aa_spent = emu->aa_spent;
// These fields may need to be correctly populated at some point // These fields may need to be correctly populated at some point
eq->aapoints_assigned = emu->aa_spent + 1; eq->aapoints_assigned = emu->aa_spent;
eq->aa_spent_general = 0; eq->aa_spent_general = 0;
eq->aa_spent_archetype = 0; eq->aa_spent_archetype = 0;
eq->aa_spent_class = 0; eq->aa_spent_class = 0;
@ -2846,58 +2846,81 @@ namespace RoF
ENCODE(OP_SendAATable) ENCODE(OP_SendAATable)
{ {
ENCODE_LENGTH_ATLEAST(SendAA_Struct); EQApplicationPacket *inapp = *p;
SETUP_VAR_ENCODE(SendAA_Struct); *p = nullptr;
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
// Check clientver field to verify this AA should be sent for SoF // the structs::SendAA_Struct includes enough space for 1 prereq which is the min even if it has no prereqs
// clientver 1 is for all clients and 5 is for Live auto prereq_size = emu->total_prereqs > 1 ? (emu->total_prereqs - 1) * 8 : 0;
if (emu->clientver <= 7) auto outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability) + prereq_size);
{ inapp->SetReadPosition(sizeof(AARankInfo_Struct)+emu->total_effects * sizeof(AARankEffect_Struct));
OUT(id);
eq->unknown004 = 1;
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); std::vector<int32> skill;
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); std::vector<int32> points;
//eq->title_sid = emu->id - emu->current_level + 1; for(auto i = 0; i < emu->total_prereqs; ++i) {
//eq->desc_sid = emu->id - emu->current_level + 1; skill.push_back(inapp->ReadUInt32());
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? -1 : (emu->sof_next_skill); points.push_back(inapp->ReadUInt32());
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? -1 : (emu->sof_next_skill);
eq->title_sid = emu->sof_next_skill;
eq->desc_sid = emu->sof_next_skill;
OUT(class_type);
OUT(cost);
OUT(seq);
OUT(current_level);
eq->prereq_skill_count = 1; // min 1
OUT(prereq_skill);
eq->prereq_minpoints_count = 1; // min 1
OUT(prereq_minpoints);
eq->type = emu->sof_type;
OUT(spellid);
eq->unknown057 = 1; // Introduced during HoT
OUT(spell_type);
OUT(spell_refresh);
OUT(classes);
OUT(berserker);
//eq->max_level = emu->sof_max_level;
OUT(max_level);
OUT(last_id);
OUT(next_id);
OUT(cost2);
eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category;
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++) {
OUT(abilities[r].skill_id);
OUT(abilities[r].base1);
OUT(abilities[r].base2);
OUT(abilities[r].slot);
}
} }
FINISH_ENCODE(); outapp->WriteUInt32(emu->id);
outapp->WriteUInt8(1);
outapp->WriteSInt32(emu->upper_hotkey_sid);
outapp->WriteSInt32(emu->lower_hotkey_sid);
outapp->WriteSInt32(emu->title_sid);
outapp->WriteSInt32(emu->desc_sid);
outapp->WriteSInt32(emu->level_req);
outapp->WriteSInt32(emu->cost);
outapp->WriteUInt32(emu->seq);
outapp->WriteUInt32(emu->current_level);
if(emu->total_prereqs) {
outapp->WriteUInt32(emu->total_prereqs);
for(auto &e : skill)
outapp->WriteSInt32(e);
outapp->WriteUInt32(emu->total_prereqs);
for(auto &e : points)
outapp->WriteSInt32(e);
}
else {
outapp->WriteUInt32(1);
outapp->WriteUInt32(0);
outapp->WriteUInt32(1);
outapp->WriteUInt32(0);
}
outapp->WriteSInt32(emu->type);
outapp->WriteSInt32(emu->spell);
outapp->WriteSInt32(1);
outapp->WriteSInt32(emu->spell_type);
outapp->WriteSInt32(emu->spell_refresh);
outapp->WriteSInt32(emu->classes);
outapp->WriteSInt32(emu->max_level);
outapp->WriteSInt32(emu->prev_id);
outapp->WriteSInt32(emu->next_id);
outapp->WriteSInt32(emu->total_cost);
outapp->WriteUInt8(0);
outapp->WriteUInt8(emu->grant_only);
outapp->WriteUInt8(0);
outapp->WriteUInt32(emu->charges);
outapp->WriteSInt32(emu->expansion);
outapp->WriteSInt32(emu->category);
outapp->WriteUInt8(0); // shroud
outapp->WriteUInt8(0); // unknown109
outapp->WriteUInt8(0); // loh
outapp->WriteUInt8(0); // unknown111
outapp->WriteUInt32(emu->total_effects);
inapp->SetReadPosition(sizeof(AARankInfo_Struct));
for(auto i = 0; i < emu->total_effects; ++i) {
outapp->WriteUInt32(inapp->ReadUInt32()); // skill_id
outapp->WriteUInt32(inapp->ReadUInt32()); // base1
outapp->WriteUInt32(inapp->ReadUInt32()); // base2
outapp->WriteUInt32(inapp->ReadUInt32()); // slot
}
dest->FastQueuePacket(&outapp);
delete inapp;
} }
ENCODE(OP_SendCharInfo) ENCODE(OP_SendCharInfo)

View File

@ -2466,7 +2466,8 @@ namespace RoF2
outapp->WriteUInt32(emu->lastlogin); outapp->WriteUInt32(emu->lastlogin);
outapp->WriteUInt32(emu->timePlayedMin); outapp->WriteUInt32(emu->timePlayedMin);
outapp->WriteUInt32(emu->timeentitledonaccount); outapp->WriteUInt32(emu->timeentitledonaccount);
outapp->WriteUInt32(0x0007ffff); // Expansion bitmask outapp->WriteUInt32(emu->expansions);
//outapp->WriteUInt32(0x0007ffff); // Expansion bitmask
outapp->WriteUInt32(structs::MAX_PP_LANGUAGE); outapp->WriteUInt32(structs::MAX_PP_LANGUAGE);
@ -2899,7 +2900,7 @@ namespace RoF2
eq->aa_spent = emu->aa_spent; eq->aa_spent = emu->aa_spent;
// These fields may need to be correctly populated at some point // These fields may need to be correctly populated at some point
eq->aapoints_assigned = emu->aa_spent + 1; eq->aapoints_assigned = emu->aa_spent;
eq->aa_spent_general = 0; eq->aa_spent_general = 0;
eq->aa_spent_archetype = 0; eq->aa_spent_archetype = 0;
eq->aa_spent_class = 0; eq->aa_spent_class = 0;
@ -2935,58 +2936,80 @@ namespace RoF2
ENCODE(OP_SendAATable) ENCODE(OP_SendAATable)
{ {
ENCODE_LENGTH_ATLEAST(SendAA_Struct); EQApplicationPacket *inapp = *p;
SETUP_VAR_ENCODE(SendAA_Struct); *p = nullptr;
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
// Check clientver field to verify this AA should be sent for SoF // the structs::SendAA_Struct includes enough space for 1 prereq which is the min even if it has no prereqs
// clientver 1 is for all clients and 5 is for Live auto prereq_size = emu->total_prereqs > 1 ? (emu->total_prereqs - 1) * 8 : 0;
if (emu->clientver <= 8) auto outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability) + prereq_size);
{ inapp->SetReadPosition(sizeof(AARankInfo_Struct)+emu->total_effects * sizeof(AARankEffect_Struct));
OUT(id);
eq->unknown004 = 1;
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); std::vector<int32> skill;
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); std::vector<int32> points;
//eq->title_sid = emu->id - emu->current_level + 1; for(auto i = 0; i < emu->total_prereqs; ++i) {
//eq->desc_sid = emu->id - emu->current_level + 1; skill.push_back(inapp->ReadUInt32());
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? -1 : (emu->sof_next_skill); points.push_back(inapp->ReadUInt32());
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? -1 : (emu->sof_next_skill);
eq->title_sid = emu->sof_next_skill;
eq->desc_sid = emu->sof_next_skill;
OUT(class_type);
OUT(cost);
OUT(seq);
OUT(current_level);
eq->prereq_skill_count = 1; // min 1
OUT(prereq_skill);
eq->prereq_minpoints_count = 1; // min 1
OUT(prereq_minpoints);
eq->type = emu->sof_type;
OUT(spellid);
eq->unknown057 = 1; // Introduced during HoT
OUT(spell_type);
OUT(spell_refresh);
OUT(classes);
OUT(berserker);
//eq->max_level = emu->sof_max_level;
OUT(max_level);
OUT(last_id);
OUT(next_id);
OUT(cost2);
eq->aa_expansion = emu->aa_expansion;
eq->special_category = emu->special_category;
OUT(total_abilities);
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
OUT(abilities[r].skill_id);
OUT(abilities[r].base1);
OUT(abilities[r].base2);
OUT(abilities[r].slot);
}
} }
FINISH_ENCODE(); outapp->WriteUInt32(emu->id);
outapp->WriteUInt8(1);
outapp->WriteSInt32(emu->upper_hotkey_sid);
outapp->WriteSInt32(emu->lower_hotkey_sid);
outapp->WriteSInt32(emu->title_sid);
outapp->WriteSInt32(emu->desc_sid);
outapp->WriteSInt32(emu->level_req);
outapp->WriteSInt32(emu->cost);
outapp->WriteUInt32(emu->seq);
outapp->WriteUInt32(emu->current_level);
if (emu->total_prereqs) {
outapp->WriteUInt32(emu->total_prereqs);
for (auto &e : skill)
outapp->WriteSInt32(e);
outapp->WriteUInt32(emu->total_prereqs);
for (auto &e : points)
outapp->WriteSInt32(e);
} else {
outapp->WriteUInt32(1);
outapp->WriteUInt32(0);
outapp->WriteUInt32(1);
outapp->WriteUInt32(0);
}
outapp->WriteSInt32(emu->type);
outapp->WriteSInt32(emu->spell);
outapp->WriteSInt32(1);
outapp->WriteSInt32(emu->spell_type);
outapp->WriteSInt32(emu->spell_refresh);
outapp->WriteSInt32(emu->classes);
outapp->WriteSInt32(emu->max_level);
outapp->WriteSInt32(emu->prev_id);
outapp->WriteSInt32(emu->next_id);
outapp->WriteSInt32(emu->total_cost);
outapp->WriteUInt8(0);
outapp->WriteUInt8(emu->grant_only);
outapp->WriteUInt8(0);
outapp->WriteUInt32(emu->charges);
outapp->WriteSInt32(emu->expansion);
outapp->WriteSInt32(emu->category);
outapp->WriteUInt8(0); // shroud
outapp->WriteUInt8(0); // unknown109
outapp->WriteUInt8(0); // loh
outapp->WriteUInt8(0); // unknown111
outapp->WriteUInt32(emu->total_effects);
inapp->SetReadPosition(sizeof(AARankInfo_Struct));
for(auto i = 0; i < emu->total_effects; ++i) {
outapp->WriteUInt32(inapp->ReadUInt32()); // skill_id
outapp->WriteUInt32(inapp->ReadUInt32()); // base1
outapp->WriteUInt32(inapp->ReadUInt32()); // base2
outapp->WriteUInt32(inapp->ReadUInt32()); // slot
}
dest->FastQueuePacket(&outapp);
delete inapp;
} }
ENCODE(OP_SendCharInfo) ENCODE(OP_SendCharInfo)

View File

@ -4289,7 +4289,7 @@ struct AA_List {
struct AA_Action { struct AA_Action {
/*00*/ uint32 action; /*00*/ uint32 action;
/*04*/ uint32 ability; /*04*/ uint32 ability;
/*08*/ uint32 unknown08; /*08*/ uint32 target_id;
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
/*16*/ /*16*/
}; };

View File

@ -4288,7 +4288,7 @@ struct AA_List {
struct AA_Action { struct AA_Action {
/*00*/ uint32 action; /*00*/ uint32 action;
/*04*/ uint32 ability; /*04*/ uint32 ability;
/*08*/ uint32 unknown08; /*08*/ uint32 target_id;
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
/*16*/ /*16*/
}; };

View File

@ -1677,8 +1677,8 @@ namespace SoD
OUT(copper_bank); OUT(copper_bank);
OUT(platinum_shared); OUT(platinum_shared);
// OUT(unknown13156[84]); // OUT(unknown13156[84]);
//OUT(expansions); OUT(expansions);
eq->expansions = 16383; //eq->expansions = 16383;
// OUT(unknown13244[12]); // OUT(unknown13244[12]);
OUT(autosplit); OUT(autosplit);
// OUT(unknown13260[16]); // OUT(unknown13260[16]);
@ -1862,55 +1862,56 @@ namespace SoD
ENCODE(OP_SendAATable) ENCODE(OP_SendAATable)
{ {
ENCODE_LENGTH_ATLEAST(SendAA_Struct); EQApplicationPacket *inapp = *p;
SETUP_VAR_ENCODE(SendAA_Struct); *p = nullptr;
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
// Check clientver field to verify this AA should be sent for SoF EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
// clientver 1 is for all clients and 5 is for SoD structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
if (emu->clientver <= 5)
{ inapp->SetReadPosition(sizeof(AARankInfo_Struct));
OUT(id); outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
eq->id = emu->id;
eq->unknown004 = 1; eq->unknown004 = 1;
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); eq->id = emu->id;
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); eq->hotkey_sid = emu->upper_hotkey_sid;
//eq->title_sid = emu->id - emu->current_level + 1; eq->hotkey_sid2 = emu->lower_hotkey_sid;
//eq->desc_sid = emu->id - emu->current_level + 1; eq->desc_sid = emu->desc_sid;
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill); eq->title_sid = emu->title_sid;
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->sof_next_skill); eq->class_type = emu->level_req;
eq->title_sid = emu->sof_next_skill; eq->cost = emu->cost;
eq->desc_sid = emu->sof_next_skill; eq->seq = emu->seq;
OUT(class_type); eq->current_level = emu->current_level;
OUT(cost); eq->type = emu->type;
OUT(seq); eq->spellid = emu->spell;
OUT(current_level); eq->spell_type = emu->spell_type;
OUT(prereq_skill); eq->spell_refresh = emu->spell_refresh;
OUT(prereq_minpoints); eq->classes = emu->classes;
eq->type = emu->sof_type; eq->max_level = emu->max_level;
OUT(spellid); eq->last_id = emu->prev_id;
OUT(spell_type); eq->next_id = emu->next_id;
OUT(spell_refresh); eq->cost2 = emu->total_cost;
OUT(classes); eq->grant_only = emu->grant_only;
OUT(berserker); eq->expendable_charges = emu->charges;
//eq->max_level = emu->sof_max_level; eq->aa_expansion = emu->expansion;
OUT(max_level); eq->special_category = emu->category;
OUT(last_id); eq->total_abilities = emu->total_effects;
OUT(next_id);
OUT(cost2); for(auto i = 0; i < eq->total_abilities; ++i) {
eq->aa_expansion = emu->aa_expansion; eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->special_category = emu->special_category; eq->abilities[i].base1 = inapp->ReadUInt32();
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number eq->abilities[i].base2 = inapp->ReadUInt32();
OUT(total_abilities); eq->abilities[i].slot = inapp->ReadUInt32();
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
OUT(abilities[r].skill_id);
OUT(abilities[r].base1);
OUT(abilities[r].base2);
OUT(abilities[r].slot);
}
} }
FINISH_ENCODE(); if(emu->total_prereqs > 0) {
eq->prereq_skill = inapp->ReadUInt32();
eq->prereq_minpoints = inapp->ReadUInt32();
}
dest->FastQueuePacket(&outapp);
delete inapp;
} }
ENCODE(OP_SendCharInfo) ENCODE(OP_SendCharInfo)

View File

@ -3813,8 +3813,7 @@ struct SendAA_Struct {
/*0049*/ uint32 spellid; /*0049*/ uint32 spellid;
/*0053*/ uint32 spell_type; /*0053*/ uint32 spell_type;
/*0057*/ uint32 spell_refresh; /*0057*/ uint32 spell_refresh;
/*0061*/ uint16 classes; /*0061*/ uint32 classes;
/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability
/*0065*/ uint32 max_level; /*0065*/ uint32 max_level;
/*0069*/ uint32 last_id; /*0069*/ uint32 last_id;
/*0073*/ uint32 next_id; /*0073*/ uint32 next_id;
@ -3840,7 +3839,7 @@ struct AA_List {
struct AA_Action { struct AA_Action {
/*00*/ uint32 action; /*00*/ uint32 action;
/*04*/ uint32 ability; /*04*/ uint32 ability;
/*08*/ uint32 unknown08; /*08*/ uint32 target_id;
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };

View File

@ -1335,8 +1335,8 @@ namespace SoF
OUT(copper_bank); OUT(copper_bank);
OUT(platinum_shared); OUT(platinum_shared);
// OUT(unknown13156[84]); // OUT(unknown13156[84]);
//OUT(expansions); OUT(expansions);
eq->expansions = 16383; //eq->expansions = 16383;
// OUT(unknown13244[12]); // OUT(unknown13244[12]);
OUT(autosplit); OUT(autosplit);
// OUT(unknown13260[16]); // OUT(unknown13260[16]);
@ -1520,56 +1520,56 @@ namespace SoF
ENCODE(OP_SendAATable) ENCODE(OP_SendAATable)
{ {
ENCODE_LENGTH_ATLEAST(SendAA_Struct); EQApplicationPacket *inapp = *p;
*p = nullptr;
AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
SETUP_VAR_ENCODE(SendAA_Struct); EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
// Check clientver field to verify this AA should be sent for SoF inapp->SetReadPosition(sizeof(AARankInfo_Struct));
// clientver 1 is for all clients and 4 is for SoF outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
if (emu->clientver <= 4)
{ eq->id = emu->id;
OUT(id);
eq->unknown004 = 1; eq->unknown004 = 1;
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); eq->id = emu->id;
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); eq->hotkey_sid = emu->upper_hotkey_sid;
//eq->title_sid = emu->id - emu->current_level + 1; eq->hotkey_sid2 = emu->lower_hotkey_sid;
//eq->desc_sid = emu->id - emu->current_level + 1; eq->desc_sid = emu->desc_sid;
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill); eq->title_sid = emu->title_sid;
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->sof_next_skill); eq->class_type = emu->level_req;
eq->title_sid = emu->sof_next_skill; eq->cost = emu->cost;
eq->desc_sid = emu->sof_next_skill; eq->seq = emu->seq;
OUT(class_type); eq->current_level = emu->current_level;
OUT(cost); eq->type = emu->type;
OUT(seq); eq->spellid = emu->spell;
OUT(current_level); eq->spell_type = emu->spell_type;
OUT(prereq_skill); eq->spell_refresh = emu->spell_refresh;
OUT(prereq_minpoints); eq->classes = emu->classes;
eq->type = emu->sof_type; eq->max_level = emu->max_level;
OUT(spellid); eq->last_id = emu->prev_id;
OUT(spell_type); eq->next_id = emu->next_id;
OUT(spell_refresh); eq->cost2 = emu->total_cost;
OUT(classes); eq->grant_only = emu->grant_only;
OUT(berserker); eq->expendable_charges = emu->charges;
//eq->max_level = emu->sof_max_level; eq->aa_expansion = emu->expansion;
OUT(max_level); eq->special_category = emu->category;
OUT(last_id); eq->total_abilities = emu->total_effects;
OUT(next_id);
OUT(cost2); for(auto i = 0; i < eq->total_abilities; ++i) {
eq->aa_expansion = emu->aa_expansion; eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->special_category = emu->special_category; eq->abilities[i].base1 = inapp->ReadUInt32();
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number eq->abilities[i].base2 = inapp->ReadUInt32();
OUT(total_abilities); eq->abilities[i].slot = inapp->ReadUInt32();
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
OUT(abilities[r].skill_id);
OUT(abilities[r].base1);
OUT(abilities[r].base2);
OUT(abilities[r].slot);
}
} }
FINISH_ENCODE(); if(emu->total_prereqs > 0) {
eq->prereq_skill = inapp->ReadUInt32();
eq->prereq_minpoints = inapp->ReadUInt32();
}
dest->FastQueuePacket(&outapp);
delete inapp;
} }
ENCODE(OP_SendCharInfo) ENCODE(OP_SendCharInfo)
@ -1665,8 +1665,6 @@ namespace SoF
emu_ptr += sizeof(CharacterSelectEntry_Struct); emu_ptr += sizeof(CharacterSelectEntry_Struct);
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct); eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
} }
FINISH_ENCODE();
} }
//hack hack hack //hack hack hack

View File

@ -3677,8 +3677,7 @@ struct SendAA_Struct {
/*0049*/ uint32 spellid; /*0049*/ uint32 spellid;
/*0053*/ uint32 spell_type; /*0053*/ uint32 spell_type;
/*0057*/ uint32 spell_refresh; /*0057*/ uint32 spell_refresh;
/*0061*/ uint16 classes; /*0061*/ uint32 classes;
/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability
/*0065*/ uint32 max_level; /*0065*/ uint32 max_level;
/*0069*/ uint32 last_id; /*0069*/ uint32 last_id;
/*0073*/ uint32 next_id; /*0073*/ uint32 next_id;
@ -3702,7 +3701,7 @@ struct AA_List {
struct AA_Action { struct AA_Action {
/*00*/ uint32 action; /*00*/ uint32 action;
/*04*/ uint32 ability; /*04*/ uint32 ability;
/*08*/ uint32 unknown08; /*08*/ uint32 target_id;
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };

View File

@ -1107,50 +1107,52 @@ namespace Titanium
ENCODE(OP_SendAATable) ENCODE(OP_SendAATable)
{ {
ENCODE_LENGTH_ATLEAST(SendAA_Struct); EQApplicationPacket *inapp = *p;
*p = nullptr;
AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
SETUP_VAR_ENCODE(SendAA_Struct); EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
// Check clientver field to verify this AA should be sent for Titanium inapp->SetReadPosition(sizeof(AARankInfo_Struct));
// clientver 1 is for all clients and 3 is for Titanium outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
if (emu->clientver <= 3)
{ eq->id = emu->id;
OUT(id);
eq->unknown004 = 1; eq->unknown004 = 1;
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1); eq->id = emu->id;
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1); eq->hotkey_sid = emu->upper_hotkey_sid;
eq->title_sid = emu->id - emu->current_level + 1; eq->hotkey_sid2 = emu->lower_hotkey_sid;
eq->desc_sid = emu->id - emu->current_level + 1; eq->desc_sid = emu->desc_sid;
OUT(class_type); eq->title_sid = emu->title_sid;
OUT(cost); eq->class_type = emu->level_req;
OUT(seq); eq->cost = emu->cost;
OUT(current_level); eq->seq = emu->seq;
OUT(prereq_skill); eq->current_level = emu->current_level;
OUT(prereq_minpoints); eq->type = emu->type;
OUT(type); eq->spellid = emu->spell;
OUT(spellid); eq->spell_type = emu->spell_type;
OUT(spell_type); eq->spell_refresh = emu->spell_refresh;
OUT(spell_refresh); eq->classes = emu->classes;
OUT(classes); eq->max_level = emu->max_level;
OUT(berserker); eq->last_id = emu->prev_id;
OUT(max_level); eq->next_id = emu->next_id;
OUT(last_id); eq->cost2 = emu->total_cost;
OUT(next_id); eq->total_abilities = emu->total_effects;
OUT(cost2);
OUT(unknown80[0]); for(auto i = 0; i < eq->total_abilities; ++i) {
OUT(unknown80[1]); eq->abilities[i].skill_id = inapp->ReadUInt32();
OUT(total_abilities); eq->abilities[i].base1 = inapp->ReadUInt32();
unsigned int r; eq->abilities[i].base2 = inapp->ReadUInt32();
for (r = 0; r < emu->total_abilities; r++) { eq->abilities[i].slot = inapp->ReadUInt32();
OUT(abilities[r].skill_id);
OUT(abilities[r].base1);
OUT(abilities[r].base2);
OUT(abilities[r].slot);
}
} }
FINISH_ENCODE(); if(emu->total_prereqs > 0) {
eq->prereq_skill = inapp->ReadUInt32();
eq->prereq_minpoints = inapp->ReadUInt32();
}
dest->FastQueuePacket(&outapp);
delete inapp;
} }
ENCODE(OP_SendCharInfo) ENCODE(OP_SendCharInfo)

View File

@ -3157,8 +3157,7 @@ struct SendAA_Struct {
/*0052*/ uint32 spellid; /*0052*/ uint32 spellid;
/*0056*/ uint32 spell_type; /*0056*/ uint32 spell_type;
/*0060*/ uint32 spell_refresh; /*0060*/ uint32 spell_refresh;
/*0064*/ uint16 classes; /*0064*/ uint32 classes;
/*0066*/ uint16 berserker; //seems to be 1 if its a berserker ability
/*0068*/ uint32 max_level; /*0068*/ uint32 max_level;
/*0072*/ uint32 last_id; /*0072*/ uint32 last_id;
/*0076*/ uint32 next_id; /*0076*/ uint32 next_id;
@ -3175,7 +3174,7 @@ struct AA_List {
struct AA_Action { struct AA_Action {
/*00*/ uint32 action; /*00*/ uint32 action;
/*04*/ uint32 ability; /*04*/ uint32 ability;
/*08*/ uint32 unknown08; /*08*/ uint32 target_id;
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };

View File

@ -1805,11 +1805,13 @@ namespace UF
//NOTE: new client supports 300 AAs, our internal rep/PP //NOTE: new client supports 300 AAs, our internal rep/PP
//only supports 240.. //only supports 240..
for (r = 0; r < MAX_PP_AA_ARRAY; r++) { for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
OUT(aa_array[r].AA); eq->aa_array[r].AA = emu->aa_array[r].AA;
OUT(aa_array[r].value); eq->aa_array[r].value = emu->aa_array[r].value;
OUT(aa_array[r].charges); eq->aa_array[r].charges = emu->aa_array[r].charges;
} }
// OUT(unknown02220[4]); // OUT(unknown02220[4]);
OUT(mana); OUT(mana);
OUT(cur_hp); OUT(cur_hp);
OUT(STR); OUT(STR);
@ -1939,8 +1941,8 @@ namespace UF
OUT(copper_bank); OUT(copper_bank);
OUT(platinum_shared); OUT(platinum_shared);
// OUT(unknown13156[84]); // OUT(unknown13156[84]);
//OUT(expansions); OUT(expansions);
eq->expansions = 0xffff; //eq->expansions = 0x1ffff;
// OUT(unknown13244[12]); // OUT(unknown13244[12]);
OUT(autosplit); OUT(autosplit);
// OUT(unknown13260[16]); // OUT(unknown13260[16]);
@ -2128,7 +2130,7 @@ namespace UF
eq->aa_spent = emu->aa_spent; eq->aa_spent = emu->aa_spent;
eq->aa_assigned = emu->aa_spent; eq->aa_assigned = emu->aa_spent;
eq->aa_spent3 = emu->aa_spent; eq->aa_spent3 = 0;
eq->unknown012 = 0; eq->unknown012 = 0;
eq->unknown016 = 0; eq->unknown016 = 0;
eq->unknown020 = 0; eq->unknown020 = 0;
@ -2145,55 +2147,56 @@ namespace UF
ENCODE(OP_SendAATable) ENCODE(OP_SendAATable)
{ {
ENCODE_LENGTH_ATLEAST(SendAA_Struct); EQApplicationPacket *inapp = *p;
SETUP_VAR_ENCODE(SendAA_Struct); *p = nullptr;
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
// Check clientver field to verify this AA should be sent for SoF EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
// clientver 1 is for all clients and 6 is for Underfoot structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
if (emu->clientver <= 6)
{ inapp->SetReadPosition(sizeof(AARankInfo_Struct));
OUT(id); outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
eq->id = emu->id;
eq->unknown004 = 1; eq->unknown004 = 1;
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); eq->id = emu->id;
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); eq->hotkey_sid = emu->upper_hotkey_sid;
//eq->title_sid = emu->id - emu->current_level + 1; eq->hotkey_sid2 = emu->lower_hotkey_sid;
//eq->desc_sid = emu->id - emu->current_level + 1; eq->desc_sid = emu->desc_sid;
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill); eq->title_sid = emu->title_sid;
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->sof_next_skill); eq->class_type = emu->level_req;
eq->title_sid = emu->sof_next_skill; eq->cost = emu->cost;
eq->desc_sid = emu->sof_next_skill; eq->seq = emu->seq;
OUT(class_type); eq->current_level = emu->current_level;
OUT(cost); eq->type = emu->type;
OUT(seq); eq->spellid = emu->spell;
OUT(current_level); eq->spell_type = emu->spell_type;
OUT(prereq_skill); eq->spell_refresh = emu->spell_refresh;
OUT(prereq_minpoints); eq->classes = emu->classes;
eq->type = emu->sof_type; eq->max_level = emu->max_level;
OUT(spellid); eq->last_id = emu->prev_id;
OUT(spell_type); eq->next_id = emu->next_id;
OUT(spell_refresh); eq->cost2 = emu->total_cost;
OUT(classes); eq->grant_only = emu->grant_only;
OUT(berserker); eq->expendable_charges = emu->charges;
//eq->max_level = emu->sof_max_level; eq->aa_expansion = emu->expansion;
OUT(max_level); eq->special_category = emu->category;
OUT(last_id); eq->total_abilities = emu->total_effects;
OUT(next_id);
OUT(cost2); for(auto i = 0; i < eq->total_abilities; ++i) {
eq->aa_expansion = emu->aa_expansion; eq->abilities[i].skill_id = inapp->ReadUInt32();
eq->special_category = emu->special_category; eq->abilities[i].base1 = inapp->ReadUInt32();
eq->expendable_charges = emu->special_category == 7 ? 1 : 0; // temp hack, this can actually be any number eq->abilities[i].base2 = inapp->ReadUInt32();
OUT(total_abilities); eq->abilities[i].slot = inapp->ReadUInt32();
unsigned int r;
for (r = 0; r < emu->total_abilities; r++) {
OUT(abilities[r].skill_id);
OUT(abilities[r].base1);
OUT(abilities[r].base2);
OUT(abilities[r].slot);
}
} }
FINISH_ENCODE(); if(emu->total_prereqs > 0) {
eq->prereq_skill = inapp->ReadUInt32();
eq->prereq_minpoints = inapp->ReadUInt32();
}
dest->FastQueuePacket(&outapp);
delete inapp;
} }
ENCODE(OP_SendCharInfo) ENCODE(OP_SendCharInfo)

View File

@ -3886,8 +3886,7 @@ struct SendAA_Struct {
/*0049*/ uint32 spellid; /*0049*/ uint32 spellid;
/*0053*/ uint32 spell_type; /*0053*/ uint32 spell_type;
/*0057*/ uint32 spell_refresh; /*0057*/ uint32 spell_refresh;
/*0061*/ uint16 classes; /*0061*/ uint32 classes;
/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability
/*0065*/ uint32 max_level; /*0065*/ uint32 max_level;
/*0069*/ uint32 last_id; /*0069*/ uint32 last_id;
/*0073*/ uint32 next_id; /*0073*/ uint32 next_id;
@ -3913,7 +3912,7 @@ struct AA_List {
struct AA_Action { struct AA_Action {
/*00*/ uint32 action; /*00*/ uint32 action;
/*04*/ uint32 ability; /*04*/ uint32 ability;
/*08*/ uint32 unknown08; /*08*/ uint32 target_id;
/*12*/ uint32 exp_value; /*12*/ uint32 exp_value;
}; };

View File

@ -139,8 +139,4 @@ protected:
std::map<pTimerType, PersistentTimer *> _list; std::map<pTimerType, PersistentTimer *> _list;
}; };
//code prettying macros
#define AA_Choose3(val, v1, v2, v3) (val==1?v1:(val==2?v2:v3))
#define AA_Choose5(val, v1, v2, v3, v4, v5) (val==1?v1:(val==2?v2:(val==3?v3:(val==4?v4:v5))))
#endif #endif

View File

@ -99,6 +99,7 @@ RULE_BOOL(Character, EnableXTargetting, true) // Enable Extended Targetting Wind
RULE_BOOL(Character, KeepLevelOverMax, false) // Don't delevel a character that has somehow gone over the level cap 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, 35) // 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_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. 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.
RULE_INT(Character, OrnamentationAugmentType, 20) //Ornamentation Augment Type RULE_INT(Character, OrnamentationAugmentType, 20) //Ornamentation Augment Type
RULE_REAL(Character, EnvironmentDamageMulipliter, 1) RULE_REAL(Character, EnvironmentDamageMulipliter, 1)
@ -185,6 +186,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, 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, 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_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_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_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. 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.

View File

@ -1682,6 +1682,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].not_extendable = atoi(row[197]) != 0; sp[tempid].not_extendable = atoi(row[197]) != 0;
sp[tempid].suspendable = atoi(row[200]) != 0; sp[tempid].suspendable = atoi(row[200]) != 0;
sp[tempid].viral_range = atoi(row[201]); sp[tempid].viral_range = atoi(row[201]);
sp[tempid].songcap = atoi(row[202]);
sp[tempid].no_block = atoi(row[205]); sp[tempid].no_block = atoi(row[205]);
sp[tempid].spellgroup=atoi(row[207]); sp[tempid].spellgroup=atoi(row[207]);
sp[tempid].rank = atoi(row[208]); sp[tempid].rank = atoi(row[208]);

View File

@ -381,47 +381,47 @@ typedef enum {
#define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance. #define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance.
#define SE_TwoHandBash 226 // *not implemented as bonus #define SE_TwoHandBash 226 // *not implemented as bonus
#define SE_ReduceSkillTimer 227 // implemented #define SE_ReduceSkillTimer 227 // implemented
//#define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling #define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling
#define SE_PersistantCasting 229 // implemented #define SE_PersistantCasting 229 // implemented
//#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability #define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability
#define SE_StunBashChance 231 // implemented - increase chance to stun from bash. #define SE_StunBashChance 231 // implemented - increase chance to stun from bash.
#define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save) #define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save)
#define SE_Metabolism 233 // implemented - Modifies food/drink consumption rates. #define SE_Metabolism 233 // implemented - Modifies food/drink consumption rates.
//#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison #define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison
#define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live.
//#define SE_FreePet 236 // not used //#define SE_FreePet 236 // not used
#define SE_GivePetGroupTarget 237 // implemented[AA] - (Pet Affinity) #define SE_GivePetGroupTarget 237 // implemented[AA] - (Pet Affinity)
#define SE_IllusionPersistence 238 // implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed. #define SE_IllusionPersistence 238 // implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed.
//#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. #define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you.
//#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.] //#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.]
#define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet. #define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet.
#define SE_IncreaseChanceMemwipe 242 // implemented - increases the chance to wipe hate with memory blurr #define SE_IncreaseChanceMemwipe 242 // implemented - increases the chance to wipe hate with memory blurr
#define SE_CharmBreakChance 243 // implemented - Total Domination #define SE_CharmBreakChance 243 // implemented - Total Domination
#define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break. #define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break.
//#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest #define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest
#define SE_SetBreathLevel 246 // *not implemented as bonus #define SE_SetBreathLevel 246 // *not implemented as bonus
#define SE_RaiseSkillCap 247 // *not implemented[AA] - adds skill over the skill cap. #define SE_RaiseSkillCap 247 // *not implemented[AA] - adds skill over the skill cap.
//#define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100) #define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100)
#define SE_SecondaryDmgInc 249 // implemented[AA] Allows off hand weapon to recieve a damage bonus (Sinister Strikes) #define SE_SecondaryDmgInc 249 // implemented[AA] Allows off hand weapon to recieve a damage bonus (Sinister Strikes)
#define SE_SpellProcChance 250 // implemented - Increase chance to proc from melee proc spells (ie Spirit of Panther) #define SE_SpellProcChance 250 // implemented - Increase chance to proc from melee proc spells (ie Spirit of Panther)
#define SE_ConsumeProjectile 251 // implemented[AA] - chance to not consume an arrow (ConsumeProjectile = 100) #define SE_ConsumeProjectile 251 // implemented[AA] - chance to not consume an arrow (ConsumeProjectile = 100)
#define SE_FrontalBackstabChance 252 // implemented[AA] - chance to perform a full damage backstab from front. #define SE_FrontalBackstabChance 252 // implemented[AA] - chance to perform a full damage backstab from front.
#define SE_FrontalBackstabMinDmg 253 // implemented[AA] - allow a frontal backstab for mininum damage. #define SE_FrontalBackstabMinDmg 253 // implemented[AA] - allow a frontal backstab for mininum damage.
#define SE_Blank 254 // implemented #define SE_Blank 254 // implemented
//#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield #define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield
//#define SE_ShroudofStealth 256 // not implemented as bonus - rogue improved invs #define SE_ShroudofStealth 256 // not implemented as bonus - rogue improved invs
//#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold #define SE_PetDiscipline 257 // not implemented as bonus - /pet hold
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab #define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
#define SE_CombatStability 259 // implemented[AA] - damage mitigation #define SE_CombatStability 259 // implemented[AA] - damage mitigation
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType #define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
#define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live) #define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live)
#define SE_RaiseStatCap 262 // implemented #define SE_RaiseStatCap 262 // implemented
//#define SE_TradeSkillMastery 263 // not implemented - lets you raise more than one tradeskill above master. #define SE_TradeSkillMastery 263 // not implemented - lets you raise more than one tradeskill above master.
//#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect #define SE_HastenedAASkill 264 // implemented
#define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled #define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled
#define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon. #define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon.
#define SE_PetDiscipline2 267 // *not implemented - /pet focus, /pet no cast #define SE_PetDiscipline2 267 // *not implemented - /pet focus, /pet no cast
//#define SE_ReduceTradeskillFail 268 // *not implemented? - reduces chance to fail with given tradeskill by a percent chance #define SE_ReduceTradeskillFail 268 // *not implemented? - reduces chance to fail with given tradeskill by a percent chance
#define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound. #define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound.
#define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo) #define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo)
#define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods #define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods
@ -434,14 +434,14 @@ typedef enum {
#define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage) #define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage)
#define SE_Flurry 279 // implemented #define SE_Flurry 279 // implemented
#define SE_PetFlurry 280 // implemented[AA] #define SE_PetFlurry 280 // implemented[AA]
//#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance #define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance
#define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent. #define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent.
#define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk #define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk
//#define SE_LoHSetHeal 284 // not used //#define SE_LoHSetHeal 284 // not used
//#define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max #define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max
#define SE_FcDamageAmt 286 // implemented - adds direct spell damage #define SE_FcDamageAmt 286 // implemented - adds direct spell damage
#define SE_SpellDurationIncByTic 287 // implemented #define SE_SpellDurationIncByTic 287 // implemented
#define SE_SpecialAttackKBProc 288 // implemented[AA] - Chance to to do a knockback from special attacks [AA Dragon Punch]. #define SE_SkillAttackProc 288 // implemented[AA] - Chance to proc spell on skill attack usage (ex. Dragon Punch)
#define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration. #define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration.
#define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap #define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap
#define SE_Purify 291 // implemented - Removes determental effects #define SE_Purify 291 // implemented - Removes determental effects
@ -515,8 +515,8 @@ typedef enum {
//#define SE_PassiveSenseTrap 359 // *not implemented - Invulnerability (Brell's Blessing) //#define SE_PassiveSenseTrap 359 // *not implemented - Invulnerability (Brell's Blessing)
#define SE_ProcOnKillShot 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level #define SE_ProcOnKillShot 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level
#define SE_SpellOnDeath 361 // implemented - casts spell on death of buffed #define SE_SpellOnDeath 361 // implemented - casts spell on death of buffed
//#define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank. #define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank.
//#define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank. #define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank.
#define SE_TripleAttackChance 364 // implemented #define SE_TripleAttackChance 364 // implemented
#define SE_ProcOnSpellKillShot 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin) #define SE_ProcOnSpellKillShot 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin)
#define SE_ShieldEquipDmgMod 366 // implemented[AA] Damage modifier to melee if shield equiped. (base1 = dmg mod , base2 = ?) ie Shield Specialist AA #define SE_ShieldEquipDmgMod 366 // implemented[AA] Damage modifier to melee if shield equiped. (base1 = dmg mod , base2 = ?) ie Shield Specialist AA
@ -525,7 +525,7 @@ typedef enum {
#define SE_CorruptionCounter 369 // implemented #define SE_CorruptionCounter 369 // implemented
#define SE_ResistCorruption 370 // implemented #define SE_ResistCorruption 370 // implemented
#define SE_AttackSpeed4 371 // implemented - stackable slow effect 'Inhibit Melee' #define SE_AttackSpeed4 371 // implemented - stackable slow effect 'Inhibit Melee'
//#define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not. #define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not.
#define SE_CastOnFadeEffectAlways 373 // implemented - Triggers if fades after natural duration OR from rune/numhits fades. #define SE_CastOnFadeEffectAlways 373 // implemented - Triggers if fades after natural duration OR from rune/numhits fades.
#define SE_ApplyEffect 374 // implemented #define SE_ApplyEffect 374 // implemented
#define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount #define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount
@ -544,7 +544,7 @@ typedef enum {
//#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) //#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA)
#define SE_FcTimerRefresh 389 // implemented - Refresh spell icons #define SE_FcTimerRefresh 389 // implemented - Refresh spell icons
//#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. //#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited.
#define SE_MeleeVulnerability 391 // implemented [Live SPA has this as LimitManaMax however that is clearly not the effect used] #define SE_LimitManaMax 391 // implemented
#define SE_FcHealAmt 392 // implemented - Adds or removes healing from spells #define SE_FcHealAmt 392 // implemented - Adds or removes healing from spells
#define SE_FcHealPctIncoming 393 // implemented - HealRate with focus restrictions. #define SE_FcHealPctIncoming 393 // implemented - HealRate with focus restrictions.
#define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. #define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions.
@ -579,7 +579,7 @@ typedef enum {
#define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type #define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type
#define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace #define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace
//#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) //#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626)
//#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window #define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window
#define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt) #define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt)
#define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc #define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc
#define SE_SkillProcSuccess 429 // implemented - chance to proc when tje skill in use successfully fires. #define SE_SkillProcSuccess 429 // implemented - chance to proc when tje skill in use successfully fires.
@ -735,8 +735,8 @@ struct SPDat_Spell_Struct
/* 198- 199 */ /* 198- 199 */
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones /* 200 */ bool suspendable; // buff is suspended in suspended buff zones
/* 201 */ int viral_range; /* 201 */ int viral_range;
/* 202 */ /* 202 */ int songcap; // individual song cap
/* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented) /* 203 */
/* 204 */ /* 204 */
/* 205 */ bool no_block; /* 205 */ bool no_block;
/* 206 */ /* 206 */

View File

@ -30,7 +30,7 @@
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/ */
#define CURRENT_BINARY_DATABASE_VERSION 9085 #define CURRENT_BINARY_DATABASE_VERSION 9086
#define COMPILE_DATE __DATE__ #define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__ #define COMPILE_TIME __TIME__
#ifndef WIN32 #ifndef WIN32

View File

@ -353,6 +353,7 @@ OP_OpenContainer=0x0000
OP_Marquee=0x502e OP_Marquee=0x502e
OP_ItemRecastDelay=0x15a9 OP_ItemRecastDelay=0x15a9
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U #OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
OP_ResetAA=0x1669
# Expeditions # Expeditions
OP_DzAddPlayer=0x4701 OP_DzAddPlayer=0x4701

View File

@ -339,7 +339,7 @@
9083|2015_06_07_aa_update.sql|SHOW COLUMNS FROM `character_alternate_abilities` LIKE 'charges'|empty| 9083|2015_06_07_aa_update.sql|SHOW COLUMNS FROM `character_alternate_abilities` LIKE 'charges'|empty|
9084|2015_06_30_runspeed_adjustments.sql|SELECT `runspeed` FROM `npc_types` WHERE `runspeed` > 3|not_empty| 9084|2015_06_30_runspeed_adjustments.sql|SELECT `runspeed` FROM `npc_types` WHERE `runspeed` > 3|not_empty|
9085|2015_7_1_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty| 9085|2015_7_1_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty|
9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty|
# Upgrade conditions: # Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not # This won't be needed after this system is implemented, but it is used database that are not

File diff suppressed because it is too large Load Diff

View File

@ -152,7 +152,13 @@ void Client::SendEnterWorld(std::string name)
void Client::SendExpansionInfo() { void Client::SendExpansionInfo() {
auto outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct)); auto outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct));
ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer; ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer;
if(RuleB(World, UseClientBasedExpansionSettings)) {
eis->Expansions = ExpansionFromClientVersion(eqs->GetClientVersion());
//eis->Expansions = ExpansionFromClientVersion(this->GetCLE.
} else {
eis->Expansions = (RuleI(World, ExpansionSettings)); eis->Expansions = (RuleI(World, ExpansionSettings));
}
QueuePacket(outapp); QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
} }

View File

@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(zone_sources SET(zone_sources
aa.cpp aa.cpp
aa_ability.cpp
aggro.cpp aggro.cpp
attack.cpp attack.cpp
beacon.cpp beacon.cpp
@ -126,6 +127,7 @@ SET(zone_sources
SET(zone_headers SET(zone_headers
aa.h aa.h
aa_ability.h
basic_functions.h basic_functions.h
beacon.h beacon.h
bot.h bot.h

File diff suppressed because it is too large Load Diff

638
zone/aa.h
View File

@ -1,27 +1,8 @@
#ifndef AA_H #ifndef AA_H
#define AA_H #define AA_H
struct AA_Ability;
struct SendAA_Struct;
#define MANA_BURN 664
#include <map>
#define MAX_SWARM_PETS 12 //this can change as long as you make more coords (swarm_pet_x/swarm_pet_y) #define MAX_SWARM_PETS 12 //this can change as long as you make more coords (swarm_pet_x/swarm_pet_y)
//this might be missing some, and some might not be used...
typedef enum { //AA Targeting Constants
aaTargetUser = 1,
aaTargetCurrent = 2, //use current target
aaTargetGroup = 3, //target group of user
aaTargetCurrentGroup = 4, //target group of current target
aaTargetPet = 5 //target the user's pet
} aaTargetType;
typedef enum { typedef enum {
aaActionNone = 0, aaActionNone = 0,
aaActionAETaunt = 1, aaActionAETaunt = 1,
@ -42,21 +23,6 @@ typedef enum {
aaActionFadingMemories = 16 aaActionFadingMemories = 16
} aaNonspellAction; } aaNonspellAction;
//use these for AAs which dont cast spells, yet need effects
//if this list grows beyond 32, more work is needed in *AAEffect
typedef enum { //AA Effect IDs
aaEffectMassGroupBuff = 1, //unused - Handled via spell effect.
aaEffectRampage,
aaEffectSharedHealth,
aaEffectFlamingArrows,
aaEffectFrostArrows,
aaEffectWarcry,
aaEffectLeechTouch,
aaEffectProjectIllusion, // unused - Handled via spell effect
_maxaaEffectType = 32
} aaEffectType;
enum { //leadership AA indexes enum { //leadership AA indexes
groupAAMarkNPC = 0, groupAAMarkNPC = 0,
groupAANPCHealth, groupAANPCHealth,
@ -133,571 +99,6 @@ static const uint8 LeadershipAACosts[_maxLeaderAA][MAX_LEADERSHIP_TIERS] = {
{ 0, 0, 0, 0, 0, 0 }, //raidAA15 { 0, 0, 0, 0, 0, 0 }, //raidAA15
}; };
/*
typedef enum { //AA IDs
aaNone = 0,
aaInnateStrength = 2, //works
aaInnateStamina = 7, //works
aaInnateAgility = 12, //works
//aaCompleteHeal = 13,/ //not implemented, but is in dbstr_us.txt
aaInnateDexterity = 17, //works
aaInnateIntelligence = 22, //works
aaInnateWisdom = 27, //works
aaInnateCharisma = 32, //works
aaInnateFireProtection = 37, //works
aaInnateColdProtection = 42, //works
aaInnateMagicProtection = 47, //works
aaInnatePoisonProtection = 52, //works
aaInnateDiseaseProtection = 57, //works
aaInnateRunSpeed = 62, //works
aaInnateRegeneration = 65, //works
aaInnateMetabolism = 68,
aaInnateLungCapacity = 71, //handled by client
aaFirstAid = 74, //untested
aaHealingAdept = 77, //untested
aaHealingGift = 80, //untested
aaSpellCastingMastery = 83, //untested
aaSpellCastingReinforcement = 86, //untested
aaMentalClarity = 89,
aaSpellCastingFury = 92, //untested
aaChanellingFocus = 95,
aaSpellCastingSubtlety = 98, //untested
aaSpellCastingExpertise = 101, //untested
aaSpellCastingDeftness = 104, //untested
aaNaturalDurability = 107, //works
aaNaturalHealing = 110, //untested
aaCombatFury = 113, //untested
aaFearResistance = 116, //untested
aaFinishingBlow = 119, //untested
aaCombatStability = 122,
aaCombatAgility = 125,
aaMassGroupBuff = 128, //untested
aaDivineResurrection = 129, //DB
aaInnateInvisToUndead = 130, //DB
aaCelestialRegeneration = 131, //untested
aaBestowDivineAura = 132, //DB
aaTurnUndead = 133, //DB
aaPurifySoul = 136, //DB
aaQuickEvacuation = 137, //untested
aaExodus = 140, //untested
aaQuickDamage = 141, //untested
aaEnhancedRoot = 144,
aaDireCharm = 145, //untested
aaCannibalization = 146, //DB
aaQuickBuff = 147, //untested
aaAlchemyMastery = 150,
aaRabidBear = 153, //DB
aaManaBurn = 154, //DB
aaImprovedFamiliar = 155, //untested, implemented?
aaNexusGate = 156, //DB
aaUnknown54 = 157,
aaPermanentIllusion = 158,
aaJewelCraftMastery = 159,
aaGatherMana = 162, //DB
aaMendCompanion = 163, //DB
aaQuickSummoning = 164, //untested
aaFrenziedBurnout = 167, //DB
aaElementalFormFire = 168, //DB
aaElementalFormWater = 171, //DB
aaElementalFormEarth = 174, //DB
aaElementalFormAir = 177, //DB
aaImprovedReclaimEnergy = 180, //untested
aaTurnSummoned = 181, //DB
aaElementalPact = 182, //DB
aaLifeBurn = 183, //DB
aaDeadMesmerization = 184, //DB
aaFearstorm = 185, //DB
aaFleshToBone = 186, //DB
aaCallToCorpse = 187, //DB
aaDivineStun = 188, //DB
aaImprovedLayOnHands = 189,
aaSlayUndead = 190,
aaActOfValor = 193, //DB
aaHolySteed = 194, //DB
aaFearless = 195,
aa2HandBash = 196, //works. handled by client?
aaInnateCamouflage = 197, //DB
aaAmbidexterity = 198, //untested
aaArcheryMastery = 199, //untested
aaFletchingMastery = 202, //removed from db?
aaEndlessQuiver = 205, //untested
aaUnholySteed = 206, //DB
aaImprovedHarmTouch = 207, //untested
aaLeechTouch = 208, //DB
aaDeathPeace = 209,
aaSoulAbrasion = 210, //untested
aaInstrumentMastery = 213, //untested
aaUnknown91 = 216, //not used
aaUnknown92 = 219, //not used
aaUnknown93 = 222, //not used
aaJamFest = 225,
aaUnknown95 = 228,
aaSonicCall = 229,
aaCriticalMend = 230, //untested
aaPurifyBody = 233, //DB
aaChainCombo = 234,
aaRapidFeign = 237, //works
aaReturnKick = 240,
aaEscape = 243, //DB
aaPoisonMastery = 244,
aaDoubleRiposte = 247, //untested
aaQuickHide = 250,
aaQuickThrow = 253, //corrected from dbstr_us.txt
aaPurgePoison = 254, //DB
aaFlurry = 255, //untested
aaRampage = 258, //untested
aaAreaTaunt = 259, //untested
aaWarcry = 260, //DB
aaBandageWound = 263, //untested
aaSpellCastingReinforcementMastery = 266, //untested
aaSpellCastingFuryMastery = 267, //untested
aaExtendedNotes = 270, //untested
aaDragonPunch = 273,
aaStrongRoot = 274, //DB
aaSingingMastery = 275, //untested
aaBodyAndMindRejuvenation = 278, //added
aaPhysicalEnhancement = 279, //untested
aaAdvTrapNegotiation = 280, //untested
aaAcrobatics = 283, //untested
aaScribbleNotes = 286,
aaChaoticStab = 287, //untested
aaPetDiscipline = 288, //added
aaHobbleofSpirits = 289, //DB
aaFrenzyofSpirit = 290, //DB
aaParagonofSpirit = 291, //DB
aaAdvancedInnateStrength = 292, //works
aaAdvancedInnateStamina = 302, //works
aaAdvancedInnateAgility = 312, //works
aaAdvancedInnateDexterity = 322, //works
aaAdvancedInnateIntelligence = 332, //works
aaAdvancedInnateWisdom = 342, //works
aaAdvancedInnateCharisma = 352, //works
aaWardingofSolusek = 362, //works
aaBlessingofEci = 372, //works
aaMarrsProtection = 382, //works
aaShroudofTheFaceless = 392, //works
aaBertoxxulousGift = 402, //works
aaNewTanaanCraftingMastery = 412,
aaPlanarPower = 418, //untested
aaPlanarDurability = 423, //added
aaInnateEnlightenment = 426, //added
aaAdvancedSpellCastingMastery = 431,//untested
aaAdvancedHealingAdept = 434, //untested
aaAdvancedHealingGift = 437, //untested
aaCoupdeGrace = 440, //added
aaFuryoftheAges = 443, //added
aaMasteryofthePast = 446, //untested
aaLightningReflexes = 449, //added
aaInnateDefense = 454, //added
aaRadiantCure = 459, //DB
aaHastenedDivinity = 462, //DB
aaHastenedTurning = 465, //DB
aaHastenedPurificationofSoul = 468, //DB
aaHastenedGathering = 471, //DB
aaHastenedRabidity = 474, //DB
aaHastenedExodus = 477, //DB
aaHastenedRoot = 480, //DB
aaHastenedMending = 483, //DB
aaHastenedBanishment = 486, //DB
aaHastenedInstigation = 489, //DB, maybe
aaFuriousRampage = 492, //DB
aaHastenedPurificationoftheBody = 495,//DB
aaHastyExit = 498, //DB
aaHastenedPurification = 501, //DB
aaFlashofSteel = 504,
aaDivineArbitration = 507, //DB
aaWrathoftheWild = 510, //DB
aaVirulentParalysis = 513, //DB
aaHarvestofDruzzil = 516, //DB
aaEldritchRune = 517, //DB
aaServantofRo = 520, //DB
aaWaketheDead = 523, //DB
aaSuspendedMinion = 526, //untested
aaSpiritCall = 528, //DB
aaCelestialRenewal = 531, //DB
aaAllegiantFamiliar = 533,
aaHandofPiety = 534, //DB
aaMithanielsBinding = 537, //untested
aaMendingoftheTranquil = 539,
aaRagingFlurry = 542,
aaGuardianoftheForest = 545, //DB
aaSpiritoftheWood = 548, //DB
aaBestialFrenzy = 551, //untested
aaHarmoniousAttack = 556, //untested
aaKnightsAdvantage = 561,
aaFerocity = 564,
aaViscidRoots = 567,
aaSionachiesCrescendo = 568, //untested
aaAyonaesTutelage = 571,
aaFeignedMinion = 574,
aaUnfailingDivinity = 577,
aaAnimationEmpathy = 580, // Implemented
aaRushtoJudgement = 583,
aaLivingShield = 586,
aaConsumptionoftheSoul = 589, //untested
aaBoastfulBellow = 592, //DB
aaFervrentBlessing = 593, //untested
aaTouchoftheWicked = 596, //untested
aaPunishingBlade = 599,
aaSpeedoftheKnight = 602,
aaShroudofStealth = 605,
aaNimbleEvasion = 606,
aaTechniqueofMasterWu = 611,
aaHostoftheElements = 616, //DB
aaCallofXuzl = 619, //DB
aaHastenedStealth = 622,
aaIngenuity = 625,
aaFleetofFoot = 628,
aaFadingMemories = 630,
aaTacticalMastery = 631,
aaTheftofLife = 634,
aaFuryofMagic = 637,
aaFuryofMagicMastery2 = 640, //whats the difference?
aaProjectIllusion = 643,
aaHeadshot = 644, //added
aaEntrap = 645, //DB
aaUnholyTouch = 646, //untested
aaTotalDomination = 649, // Implemented
aaStalwartEndurance = 652, //implemented as bonus
aaQuickSummoning2 = 655, //whats the difference?
aaMentalClarity2 = 658, //whats the difference?
aaInnateRegeneration2 = 661, //whats the difference?
aaManaBurn2 = 664, //whats the difference?
aaExtendedNotes2 = 665, //not implemented - later expansions replaced Extended Notes with this.
aaSionachiesCrescendo2 = 668, //not implemented - later expansions replaced Sionachies Crescendo with this.
aaImprovedReclaimEnergy2 = 671, //whats the difference? untetsed
aaSwiftJourney = 672, //implemented as bonus
aaConvalescence = 674, //added 9/26/08
aaLastingBreath = 676, //handled by client
aaPackrat = 678, //added 9/29/08
aaHeightenedEndurance = 683,
aaWeaponAffinity = 686, //implemented
aaSecondaryForte = 691,
aaPersistantCasting = 692,
aaTuneofPursuance = 695,
aaImprovedInstrumentMastery = 700,
aaImprovedSingingMastery =701,
aaExultantBellowing = 702,
aaEchoofTaelosia = 707,
aaInternalMetronome = 710, //In 2006 this AA was removed.
aaPiousSupplication = 715,
aaBeastialAlignment = 718, //untested
aaWrathofXuzl = 721,
aaFeralSwipe = 723, //DB?
aaWardersFury = 724,
aaWardersAlacrity = 729,
aaPetAffinity = 734, // Implemented
aaMasteryofthePast2 = 735, //whats the difference?
aaSpellCastingSubtlety2 = 738, //whats the difference?
aaTouchoftheDivine = 741,
aaDivineAvatar = 746, //DB
aaExquisiteBenediction = 749, //DB
aaQuickenedCuring = 754,
aaNaturesBoon = 757, //DB
aaAdvancedTracking = 762,
aaCriticalAffliction = 767,
aaFuryofMagicMastery = 770, //whats the difference?
aaDoppelganger = 773,
aaEnchancedForgetfulness = 776,
aaMesmerizationMastery = 781,
aaQuickMassGroupBuff = 782,
aaSharedHealth = 785,
aaElementalFury = 790,
aaElementalAlacrity = 795,
aaElementalAgility = 800,
aaElementalDurability = 803,
aaSinisterStrikes = 806,
aaStrikethrough = 807,
aaStonewall = 810,
aaRapidStrikes = 815,
aaKickMastery = 820,
aaHightenedAwareness = 823,
aaDestructiveForce = 828, //DB
aaSwarmofDecay = 831, //DB
aaDeathsFury = 834,
aaQuickeningofDeath = 839,
aaAdvancedTheftofLife = 844,
aaTripleBackstab = 846,
aaHastenedPiety = 849,
aaImmobilizingBash = 852,
aaViciousSmash = 855,
aaRadiantCure2 = 860, //whats the difference?
aaPurification = 863,
aaPrecisionofthePathfinder = 864,
aaCoatofThistles = 867,
aaFlamingArrows = 872, //untested
aaFrostArrows = 875, //untested
aaSeizedOpportunity = 878,
aaTrapCircumvention = 881,
aaImprovedHastyExit = 886,
aaVirulentVenom = 888,
aaImprovedConsumptionofSoul = 893,
aaIntenseHatred = 895,
aaAdvancedSpiritCall = 900,
aaCalloftheAncients = 902, //DB
aaSturdiness = 907,
aaWarlordsTenacity = 912, //DB
aaStrengthenedStrike = 915,
aaExtendedShielding = 918,
aaRosFlamingFamiliar = 921, //DB
aaEcisIcyFamiliar = 922, //DB
aaDruzzilsMysticalFamiliar = 923, //DB
aaAdvancedFuryofMagicMastery = 924, //added 9/29/08
aaWardofDestruction = 926, //DB
aaFrenziedDevastation = 931, //DB
aaCombatFury2 = 934, //whats the difference?
aaCombatFury3 = 937, //whats the difference?
aaCombatFury4 = 940, //whats the difference?
aaFuryoftheAges2 = 943, //whats the difference?
aaFuryoftheAges3 = 946, //whats the difference?
aaFuryoftheAges4 = 949, //whats the difference?
aaPlanarDurability2 = 952, //whats the difference?
aaInnateEnlightenment2 = 955, //whats the difference?
aaDireCharm2 = 960, //whats the difference?
aaDireCharm3 = 961, //whats the difference?
aaTouchoftheDivine2 = 962, //whats the difference?
aaTouchofDecay = 967,
aaCalloftheAncients2 = 970, //whats the difference?
aaImprovedVision = 975,
aaEternalBreath = 978, //handled by client
aaBlacksmithingMastery = 979, //added 9/29/08
aaBakingMastery = 982, //added 9/29/08
aaBrewingMastery = 985, //added 9/29/08
aaFletchingMastery2 = 988, //added 9/29/08
aaPotteryMastery = 991, //added 9/29/08
aaTailoringMastery = 994, //added 9/29/08
aaSalvage = 997,
aaOrigin = 1000, //spell
aaChaoticPotential = 1001, //added
aaDiscordantDefiance = 1006, //added 9/29/08
aaTrialsofMataMuram = 1011,
aaMysticalAttuning = 1021,
aaDelayDeath = 1026,
aaHealthyAura = 1031,
aaFitness = 1036,
aaVeteransWrath = 1041, //added 9/29/08
aaVeteransWrath2 = 1044, //whats the difference?
aaVeteransWrath3 = 1047, //whats the difference?
aaVeteransWrath4 = 1050, //whats the difference?
aaDeathblow = 1053,
aaReflexiveMastery = 1061,
aaDefensiveInstincts = 1066,
aaMnemonicRetention = 1071, //Implemented
aaExpansiveMind = 1072, //added 9/29/08
aaSleightofHand = 1077,
aaSleightofHand2 = 1080, //whats the difference?
aaHealingAdeptMastery = 1083,
aaHealingGiftMastery = 1086,
aaArcaneTongues = 1089,
aaMasterofDisguise = 1092,
aaSlipperyAttacks = 1093,
aaImprovedCriticalAffliction = 1099,
aaFortifiedBellowing = 1102,
aaFuryofMagic2 = 1107, //whats the difference?
aaDanceofBlades = 1110,
aaShieldofNotes = 1116,
aaRoarofThunder = 1119,
aaPersistentMinion = 1122,
aaPerfectionofSpirit = 1123,
aaReplentishCompanion = 1126,
aaAdvancedPetDiscipline = 1129,
aaThrowingMastery = 1131,
aaBlurofAxes = 1134,
aaHastenedWarCry = 1137,
aaDeadAim = 1140,
aaFrenziedDefense = 1143,
aaTirelessSprint = 1146,
aaDesperation = 1149,
aaUntamedRage = 1150,
aaEchoingCries = 1155,
aaViciousFrenzy = 1158,
aaCrazedOnslaught = 1163,
aaOverwhelmingAttack = 1172,
aaFuriousRage = 1175,
aaBloodPact = 1178,
aaShieldingResistance = 1181,
aaHealingBoon = 1186,
aaResplendentCure = 1189,
aaCelestialHammer = 1192,
aaDivineRetribution = 1195,
aaCelestialRejuvination = 1203,
aaFerventBenediction = 1206,
aaSanctuary = 1209,
aaDestructiveFury = 1210, //added 9/29/08
aaDestructiveFury2 = 1213, //whats the difference?
aaBoonoftheForest = 1222,
aaSpiritoftheGrove = 1225,
aaCalloftheWild = 1228,
aaSecondaryRecall = 1229,
aaNaturesBounty = 1230,
aaStasis = 1233,
aaColorShock = 1239,
aaMindOverMatter = 1242,
aaSoothingWords = 1245,
aaElementalSwarm = 1248,
aaHeartofFlames = 1251,
aaHeartofVapor = 1252,
aaHeartofIce = 1253,
aaHeartofStone = 1254,
aaImitateDeath = 1255,
aaCripplingStrike = 1256,
aaStunningKick = 1259,
aaEyeGouge = 1262,
aaIronKicks = 1265,
aaStyleoftheMimic = 1268,
aaDeathPeace2 = 1272, //whats the difference?
aaArmyoftheDead = 1274,
aaCelestialStun = 1277,
aaHandofDevotion = 1278,
aaSteadfastWill = 1284,
aaShieldBlock = 1287,
aaScoutsEfficiency = 1290,
aaGuardianoftheGlade = 1293,
aaTrackingMastery = 1296,
aaFlurryofKnives = 1301,
aaPrecision = 1304,
aaNervesofSteel = 1307,
aaTouchoftheCursed = 1313,
aaSpiritualCorrosion = 1316,
aaSoulThief = 1319,
aaSpiritualChanneling = 1323,
aaBoonoftheAncients = 1324,
aaAncestralAid = 1327,
aaResoluteDefiance = 1330,
aaPresstheAttack = 1333,
aaMindCrash = 1334,
aaProlongedDestruction = 1337,
aaRosGreaterFamiliar = 1340,
aaEcisGreaterFamiliar = 1341,
aaDruzzilsGreaterFamiliar = 1342,
aaTeleportBind = 1343,
aaDevotedFamiliar = 1344,
aaAuspiceoftheHunter = 1345,
aaSavageSpirit = 1348,
aaPresstheAttack2 = 1351, //whats the difference?
aaCripplingStrike2 = 1352, //whats the difference?
aaStunningKick2 = 1353, //whats the difference?
aaEyeGouge2 = 1358, //whats the difference?
//Dragons of Norrath
//good info here: http://www.eqthieves.com/exp-don-progression.htm and here: http://everquest.allakhazam.com/db/guides.html?guide=811
aaGiftoftheDarkReign = 1361, //from dbstr_us.txt
aaTenacityoftheDarkReign = 1362, //from dbstr_us.txt
aaEmbraceoftheDarkReign = 1363, //from dbstr_us.txt
aaPoweroftheDarkReign = 1364, //from dbstr_us.txt
aaFervoroftheDarkReign = 1365, //from dbstr_us.txt
aaGiftoftheKeepers = 1366, //from dbstr_us.txt
aaValoroftheKeepers = 1367, //from dbstr_us.txt
aaEmbraceoftheKeepers = 1368, //from dbstr_us.txt
aaPoweroftheKeepers = 1369, //from dbstr_us.txt
aaSanctityoftheKeepers = 1370, //from dbstr_us.txt
//Veteran AAs
aaLessonoftheDevoted = 1371, //from dbstr_us.txt
aaInfusionoftheFaithful = 1372, //from dbstr_us.txt
aaChaoticJester = 1373, //from dbstr_us.txt
aaExpedientRecovery = 1374, //from dbstr_us.txt
aaSteadfastServant = 1375, //from dbstr_us.txt
aaStaunchRecovery = 1376, //from dbstr_us.txt
aaIntensityoftheResolute = 1377, //from dbstr_us.txt
//Depths of Darkhollow
//the following 5 look to be used as flags for completion of the Blood Raids for access to the Demiplane of Blood
//quest info here: http://everquest.allakhazam.com/db/quest.html?quest=3582
//"You must also complete the five Blood Raids in any order: The Council of Nine, Emperor Draygun, Bloodeye, Matriarch Shyra, Sendaii, the Hive Queen"
//"The AA's you receive are: Curse of Blood (1/5), Affliction of Blood (2/5), Torment of Blood (3/5), Temptation of Blood (4/5), Invitation of Blood (5/5)."
aaCurseofBlood = 1378, //from dbstr_us.txt
aaAfflictionofBlood = 1379, //from dbstr_us.txt
aaTormentofBlood = 1380, //from dbstr_us.txt
aaTemptationofBlood = 1381, //from dbstr_us.txt
aaInvitationofBlood = 1382, //from dbstr_us.txt
aaTurnUndead2 = 1383, //from dbstr_us.txt, Class AA changed in DoD
aaWrackUndead = 1386, //from dbstr_us.txt, PoP Class AA changed in DoD
aaEradicateUndead = 1387, //from dbstr_us.txt
aaInnateSeeInvis = 1388, //from dbstr_us.txt
aaProlongedMortality = 1389, //from dbstr_us.txt
aaPrecognition = 1394, //from dbstr_us.txt
aaThickSkin = 1399, //from dbstr_us.txt
aaSilentCasting = 1404, //from dbstr_us.txt
aaSilentCasting2 = 1409, //from dbstr_us.txt
aaHastenedMindCrash = 1414, //from dbstr_us.txt
aaFieldDressing = 1417, //from dbstr_us.txt
aaBandageWounds = 1420, //from dbstr_us.txt
aaCascadingRage = 1425, //from dbstr_us.txt
aaElementalFerocity = 1430, //from dbstr_us.txt
aaGiftofMana = 1435, //from dbstr_us.txt
aaRuneofShadows = 1440, //from dbstr_us.txt
aaChannelingMastery = 1445, //from dbstr_us.txt
aaConservation = 1453, //from dbstr_us.txt
aaCryofBattle = 1458, //from dbstr_us.txt
aaWardofPurity = 1459, //from dbstr_us.txt
aaTurnSummoned2 = 1462, //from dbstr_us.txt
aaWrackSummoned = 1465, //from dbstr_us.txt
aaEradicateSummoned = 1466, //from dbstr_us.txt
aaWardersSavagery = 1467, //from dbstr_us.txt
aaShackleofSpirits = 1470, //from dbstr_us.txt
aaHastenedThunder = 1471, //from dbstr_us.txt
aaTranslocationalAnchor = 1474, //from dbstr_us.txt
aaStealthyGetaway = 1477, //from dbstr_us.txt
aaPyromancy = 1478, //from dbstr_us.txt
aaMasteryofFury = 1483, //from dbstr_us.txt
aaAbundantHealing = 1486, //from dbstr_us.txt
aaGreaterAvatar = 1491, //from dbstr_us.txt
aaSharedCamouflage = 1494, //from dbstr_us.txt
aaConvergenceofSpirits = 1495, //from dbstr_us.txt
aaNaturesGuardian = 1498, //from dbstr_us.txt
aaEdictofCommand = 1501, //from dbstr_us.txt
aaExtendedBurnout = 1504, //from dbstr_us.txt
aaGuardianofRo = 1507, //from dbstr_us.txt
aaBloodMagic = 1510, //from dbstr_us.txt
aaGraverobbing = 1511, //from dbstr_us.txt
aaAfflictionMastery = 1514, //from dbstr_us.txt
aaGreaterRabidBear = 1517, //from dbstr_us.txt
aaAncestralGuard = 1520, //from dbstr_us.txt
aaCloakofLight = 1523, //from dbstr_us.txt
aaVanquishUndead = 1524, //from dbstr_us.txt
aaCloakofShadows = 1527, //from dbstr_us.txt
aaWillfulDeath = 1528, //from dbstr_us.txt
aaSwiftBlade = 1533, //from dbstr_us.txt
aaWickedBlade = 1536, //from dbstr_us.txt
aaForcedOpening = 1539, //from dbstr_us.txt
aaAppraisal = 1542, //from dbstr_us.txt
aaPreciseStrikes = 1543, //from dbstr_us.txt
aaHastenedDeath = 1546, //from dbstr_us.txt
aaUnflinchingResolve = 1549, //from dbstr_us.txt
aaWeightlessSteps = 1552, //from dbstr_us.txt
aaHastenedBlades = 1555, //from dbstr_us.txt
aaImprovedHarmoniousAttack = 1563, //from dbstr_us.txt
aaImprovedBestialFrenzy = 1566, //from dbstr_us.txt
aaSongofStone = 1569, //from dbstr_us.txt
aaDeepSleep = 1572, //from dbstr_us.txt
aaCompanionsGift = 1577, //from dbstr_us.txt
aaHastenedDefiance = 1583, //from dbstr_us.txt
aaDauntlessPerseverance = 1586, //from dbstr_us.txt
aaConcentration = 1587, //from dbstr_us.txt
aaEnhancedAggression = 1592, //from dbstr_us.txt
aaCallofChallenge = 1597, //from dbstr_us.txt
aaCacophony = 1598, //from dbstr_us.txt
aaImprovedHeadshot = 1601, //from dbstr_us.txt
aaAnatomy = 1604, //from dbstr_us.txt
aaFetterofSpirits = 1607, //from dbstr_us.txt
aaTrickShot = 1608, //from dbstr_us.txt
aaLightningStrikes = 1616, //from dbstr_us.txt
aaRelentlessAssault = 1621, //from dbstr_us.txt
aaKnightsExpertise = 1624, //from dbstr_us.txt
aaSelosEnduringCadence = 1627, //from dbstr_us.txt
aaHarmTouch = 7800, //from dbstr_us.txt
aaLayonHands = 7850, //from dbstr_us.txt
aaLayonHandsRank16 = 7866,
aaHighestID //this should always be last, and should always
//follow the highest AA ID
} aaID;
*/
typedef enum { //AA IDs typedef enum { //AA IDs
aaNone =0, aaNone =0,
aaInnateStrength =2,//implemented as bonus aaInnateStrength =2,//implemented as bonus
@ -2109,21 +1510,6 @@ typedef enum { //AA IDs
//follow the highest AA ID //follow the highest AA ID
} aaID; } aaID;
//Structure representing the database's AA actions
struct AA_DBAction {
uint32 reuse_time; //in seconds
uint16 spell_id; //spell to cast, SPELL_UNKNOWN=no spell
aaTargetType target; //from aaTargetType
aaNonspellAction action; //non-spell action to take
uint16 mana_cost; //mana the NON-SPELL action costs
uint16 duration; //duration of NON-SPELL effect, 0=N/A
aaID redux_aa; //AA which reduces reuse time
int32 redux_rate; //%/point in redux_aa reduction in reuse time
aaID redux_aa2; //AA which reduces reuse time
int32 redux_rate2; //%/point in redux_aa reduction in reuse time
};
//Structure representing the database's swarm pet configs //Structure representing the database's swarm pet configs
struct AA_SwarmPet { struct AA_SwarmPet {
uint8 count; //number to summon uint8 count; //number to summon
@ -2131,23 +1517,6 @@ struct AA_SwarmPet {
uint16 duration; //how long they last, in seconds uint16 duration; //how long they last, in seconds
}; };
struct AALevelCost_Struct
{
uint32 Level;
uint32 Cost;
};
//assumes that no activatable aa.has more than 5 ranks
#define MAX_AA_ACTION_RANKS 20
extern AA_DBAction AA_Actions[aaHighestID][MAX_AA_ACTION_RANKS]; //[aaid][rank]
extern std::map<uint16, AA_SwarmPet> AA_SwarmPets; //key=spell_id
#define AA_Choose3(val, v1, v2, v3) (val==1?v1:(val==2?v2:v3))
extern std::map<uint32,SendAA_Struct*>aas_send;
extern std::map<uint32, std::map<uint32, AA_Ability> > aa_effects;
extern std::map<uint32, AALevelCost_Struct> AARequiredLevelAndCost;
enum { //values of AA_Action.action enum { //values of AA_Action.action
aaActionActivate = 0, aaActionActivate = 0,
aaActionSetEXP = 1, aaActionSetEXP = 1,
@ -2167,4 +1536,11 @@ public:
uint32 owner_id; uint32 owner_id;
}; };
enum AATimers
{
aaTimerRampage,
aaTimerWarcry,
aaTimerMax
};
#endif #endif

70
zone/aa_ability.cpp Normal file
View File

@ -0,0 +1,70 @@
/* 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 "masterentity.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(current_level == 0)
return nullptr;
if(!first)
return nullptr;
int i = 1;
Rank *current = first;
while(current->next) {
if(i == current_level) {
break;
}
i++;
current = current->next;
}
return current;
}
int AA::Ability::GetMaxLevel(Mob *who) {
int max_level = 0;
Rank *current = first;
while(current) {
if(!who->CanUseAlternateAdvancementRank(current)) {
return max_level;
}
max_level++;
current = current->next;
}
return max_level;
}

61
zone/aa_ability.h Normal file
View File

@ -0,0 +1,61 @@
/* 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_ABILITY_H
#define EQEMU_ZONE_AA_ABILITY_H
#include "../common/global_define.h"
#include <unordered_map>
#include <vector>
#include <memory>
#include "aa_rank_effects.h"
#include "aa_rank.h"
class Mob;
namespace AA
{
class Ability
{
public:
Ability() { }
~Ability() { }
Rank *GetMaxRank();
Rank *GetRankByPointsSpent(int current_level);
int GetMaxLevel(Mob *who);
int id;
std::string name;
int category;
int classes;
int races;
int deities;
int drakkin_heritage;
int status;
bool grant_only;
int type;
int charges;
int first_rank_id;
Rank *first;
};
}
#endif

56
zone/aa_rank.h Normal file
View File

@ -0,0 +1,56 @@
/* 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_H
#define EQEMU_ZONE_AA_RANK_H
namespace AA
{
class Ability;
class Rank
{
public:
Rank() { }
~Rank() { }
int id;
int upper_hotkey_sid;
int lower_hotkey_sid;
int title_sid;
int desc_sid;
int cost;
int level_req;
int spell;
int spell_type;
int recast_time;
int prev_id;
Rank *prev;
int next_id;
Rank *next;
int current_value;
int expansion;
int total_cost;
Ability *base_ability;
std::vector<RankEffect> effects;
std::map<int, int> prereqs;
};
}
#endif

38
zone/aa_rank_effects.h Normal file
View File

@ -0,0 +1,38 @@
/* 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_EFFECTS_H
#define EQEMU_ZONE_AA_RANK_EFFECTS_H
#include "../common/global_define.h"
#include <string>
namespace AA
{
struct RankEffect
{
int slot;
int effect_id;
int base1;
int base2;
};
}
#endif

View File

@ -1372,6 +1372,13 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
////// Send Attack Damage ////// Send Attack Damage
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
if (damage > 0 && aabonuses.SkillAttackProc[0] && aabonuses.SkillAttackProc[1] == skillinuse &&
IsValidSpell(aabonuses.SkillAttackProc[2])) {
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[2], other, 10, 0, -1,
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
}
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse); other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
if (IsDead()) return false; if (IsDead()) return false;
@ -3512,14 +3519,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
if(damage > 0) { if(damage > 0) {
//if there is some damage being done and theres an attacker involved //if there is some damage being done and theres an attacker involved
if(attacker) { if(attacker) {
if(spell_id == SPELL_HARM_TOUCH2 && attacker->IsClient() && attacker->CastToClient()->CheckAAEffect(aaEffectLeechTouch)){
int healed = damage;
healed = attacker->GetActSpellHealing(spell_id, healed);
attacker->HealDamage(healed);
entity_list.MessageClose(this, true, 300, MT_Emote, "%s beams a smile at %s", attacker->GetCleanName(), this->GetCleanName() );
attacker->CastToClient()->DisableAAEffect(aaEffectLeechTouch);
}
// if spell is lifetap add hp to the caster // if spell is lifetap add hp to the caster
if (spell_id != SPELL_UNKNOWN && IsLifetapSpell( spell_id )) { if (spell_id != SPELL_UNKNOWN && IsLifetapSpell( spell_id )) {
int healed = damage; int healed = damage;
@ -4416,42 +4415,55 @@ bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse)
return false; return false;
} }
void Mob::DoRiposte(Mob* defender) { void Mob::DoRiposte(Mob *defender)
{
Log.Out(Logs::Detail, Logs::Combat, "Preforming a riposte"); Log.Out(Logs::Detail, Logs::Combat, "Preforming a riposte");
if (!defender) if (!defender)
return; return;
defender->Attack(this, MainPrimary, true); defender->Attack(this, MainPrimary, true);
if (HasDied()) return; if (HasDied())
return;
int32 DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[0] + // this effect isn't used on live? See no AAs or spells
defender->spellbonuses.GiveDoubleRiposte[0] + int32 DoubleRipChance = defender->aabonuses.DoubleRiposte + defender->spellbonuses.DoubleRiposte +
defender->itembonuses.GiveDoubleRiposte[0];
DoubleRipChance = defender->aabonuses.DoubleRiposte +
defender->spellbonuses.DoubleRiposte +
defender->itembonuses.DoubleRiposte; defender->itembonuses.DoubleRiposte;
//Live AA - Double Riposte if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) {
if(DoubleRipChance && zone->random.Roll(DoubleRipChance)) { Log.Out(Logs::Detail, Logs::Combat,
Log.Out(Logs::Detail, Logs::Combat, "Preforming a double riposed (%d percent chance)", DoubleRipChance); "Preforming a double riposted from SE_DoubleRiposte (%d percent chance)", DoubleRipChance);
defender->Attack(this, MainPrimary, true); defender->Attack(this, MainPrimary, true);
if (HasDied()) return; if (HasDied())
return;
} }
//Double Riposte effect, allows for a chance to do RIPOSTE with a skill specfic special attack (ie Return Kick). DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[0] + defender->spellbonuses.GiveDoubleRiposte[0] +
//Coded narrowly: Limit to one per client. Limit AA only. [1 = Skill Attack Chance, 2 = Skill] defender->itembonuses.GiveDoubleRiposte[0];
// Live AA - Double Riposte
if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) {
Log.Out(Logs::Detail, Logs::Combat,
"Preforming a double riposted from SE_GiveDoubleRiposte base1 == 0 (%d percent chance)",
DoubleRipChance);
defender->Attack(this, MainPrimary, true);
if (HasDied())
return;
}
// Double Riposte effect, allows for a chance to do RIPOSTE with a skill specific special attack (ie Return Kick).
// Coded narrowly: Limit to one per client. Limit AA only. [1 = Skill Attack Chance, 2 = Skill]
DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[1]; DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[1];
if(DoubleRipChance && zone->random.Roll(DoubleRipChance)) { if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) {
Log.Out(Logs::Detail, Logs::Combat, "Preforming a return SPECIAL ATTACK (%d percent chance)", DoubleRipChance); Log.Out(Logs::Detail, Logs::Combat, "Preforming a return SPECIAL ATTACK (%d percent chance)",
DoubleRipChance);
if (defender->GetClass() == MONK) if (defender->GetClass() == MONK)
defender->MonkSpecialAttack(this, defender->aabonuses.GiveDoubleRiposte[2]); defender->MonkSpecialAttack(this, defender->aabonuses.GiveDoubleRiposte[2]);
else if (defender->IsClient()) else if (defender->IsClient() && defender->CastToClient()->HasSkill((SkillUseTypes)defender->aabonuses.GiveDoubleRiposte[2]))
defender->CastToClient()->DoClassAttacks(this,defender->aabonuses.GiveDoubleRiposte[2], true); defender->CastToClient()->DoClassAttacks(this, defender->aabonuses.GiveDoubleRiposte[2], true);
} }
} }
@ -4643,7 +4655,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
if (IsClient() && aabonuses.LimitToSkill[skill]){ if (IsClient() && aabonuses.LimitToSkill[skill]){
CanProc = true; CanProc = true;
uint32 effect = 0; uint32 effect_id = 0;
int32 base1 = 0; int32 base1 = 0;
int32 base2 = 0; int32 base2 = 0;
uint32 slot = 0; uint32 slot = 0;
@ -4662,22 +4674,26 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
proc_spell_id = 0; proc_spell_id = 0;
ProcMod = 0; ProcMod = 0;
std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aaid); for(auto &rank_info : aa_ranks) {
if(find_iter == aa_effects.end()) auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_info.first, rank_info.second.first);
break; auto ability = ability_rank.first;
auto rank = ability_rank.second;
for (std::map<uint32, AA_Ability>::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) { if(!ability) {
effect = iter->second.skill_id; continue;
base1 = iter->second.base1; }
base2 = iter->second.base2;
slot = iter->second.slot;
if (effect == SE_SkillProc || effect == SE_SkillProcSuccess) { for(auto &effect : rank->effects) {
effect_id = effect.effect_id;
base1 = effect.base1;
base2 = effect.base2;
slot = effect.slot;
if(effect_id == SE_SkillProc || effect_id == SE_SkillProcSuccess) {
proc_spell_id = base1; proc_spell_id = base1;
ProcMod = static_cast<float>(base2); ProcMod = static_cast<float>(base2);
} }
else if(effect_id == SE_LimitToSkill && base1 <= HIGHEST_SKILL) {
else if (effect == SE_LimitToSkill && base1 <= HIGHEST_SKILL) {
if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) { if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) {
float final_chance = chance * (ProcMod / 100.0f); float final_chance = chance * (ProcMod / 100.0f);
@ -4697,6 +4713,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
} }
} }
} }
}
} }
float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) { float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
@ -5042,3 +5059,39 @@ void NPC::SetAttackTimer()
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
} }
} }
void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
{
if (!target)
return;
Attack(target, hand, false, false, IsFromSpell);
if (CanThisClassDoubleAttack()) {
CheckIncreaseSkill(SkillDoubleAttack, target, -10);
if (CheckDoubleAttack())
Attack(target, hand, false, false, IsFromSpell);
if (hand == MainPrimary && GetLevel() >= 60 &&
(GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER) &&
CheckDoubleAttack(true))
Attack(target, hand, false, false, IsFromSpell);
}
if (hand == MainPrimary) {
auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance;
if (flurrychance && zone->random.Roll(flurrychance)) {
Message_StringID(MT_NPCFlurry, YOU_FLURRY);
Attack(target, hand, false, false, IsFromSpell);
Attack(target, hand, false, false, IsFromSpell);
}
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance;
if (extraattackchance) {
auto wpn = GetInv().GetItem(MainPrimary);
if (wpn && (wpn->GetItem()->ItemType == ItemType2HBlunt ||
wpn->GetItem()->ItemType == ItemType2HSlash ||
wpn->GetItem()->ItemType == ItemType2HPiercing))
if (zone->random.Roll(extraattackchance))
Attack(target, hand, false, false, IsFromSpell);
}
}
}

View File

@ -42,6 +42,7 @@
void Mob::CalcBonuses() void Mob::CalcBonuses()
{ {
CalcSpellBonuses(&spellbonuses); CalcSpellBonuses(&spellbonuses);
CalcAABonuses(&aabonuses);
CalcMaxHP(); CalcMaxHP();
CalcMaxMana(); CalcMaxMana();
SetAttackTimer(); SetAttackTimer();
@ -51,9 +52,7 @@ void Mob::CalcBonuses()
void NPC::CalcBonuses() void NPC::CalcBonuses()
{ {
Mob::CalcBonuses(); memset(&itembonuses, 0, sizeof(StatBonuses));
memset(&aabonuses, 0, sizeof(StatBonuses));
if(RuleB(NPC, UseItemBonusesForNonPets)){ if(RuleB(NPC, UseItemBonusesForNonPets)){
memset(&itembonuses, 0, sizeof(StatBonuses)); memset(&itembonuses, 0, sizeof(StatBonuses));
CalcItemBonuses(&itembonuses); CalcItemBonuses(&itembonuses);
@ -74,12 +73,8 @@ void Client::CalcBonuses()
memset(&itembonuses, 0, sizeof(StatBonuses)); memset(&itembonuses, 0, sizeof(StatBonuses));
CalcItemBonuses(&itembonuses); CalcItemBonuses(&itembonuses);
CalcEdibleBonuses(&itembonuses); CalcEdibleBonuses(&itembonuses);
CalcSpellBonuses(&spellbonuses); CalcSpellBonuses(&spellbonuses);
CalcAABonuses(&aabonuses);
Log.Out(Logs::Detail, Logs::AA, "Calculating AA Bonuses for %s.", this->GetCleanName());
CalcAABonuses(&aabonuses); //we're not quite ready for this
Log.Out(Logs::Detail, Logs::AA, "Finished calculating AA Bonuses for %s.", this->GetCleanName());
ProcessItemCaps(); // caps that depend on spell/aa bonuses ProcessItemCaps(); // caps that depend on spell/aa bonuses
@ -113,6 +108,9 @@ void Client::CalcBonuses()
rooted = FindType(SE_Root); rooted = FindType(SE_Root);
XPRate = 100 + spellbonuses.XPRateMod; XPRate = 100 + spellbonuses.XPRateMod;
if (GetMaxXTargets() != 5 + aabonuses.extra_xtargets)
SetMaxXTargets(5 + aabonuses.extra_xtargets);
} }
int Client::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat) int Client::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat)
@ -632,90 +630,83 @@ void Client::CalcEdibleBonuses(StatBonuses* newbon) {
} }
} }
void Client::CalcAABonuses(StatBonuses* newbon) { void Mob::CalcAABonuses(StatBonuses *newbon)
memset(newbon, 0, sizeof(StatBonuses)); //start fresh {
memset(newbon, 0, sizeof(StatBonuses)); // start fresh
int i; for (const auto &aa : aa_ranks) {
uint32 slots = 0; auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
uint32 aa_AA = 0; auto ability = ability_rank.first;
uint32 aa_value = 0; auto rank = ability_rank.second;
if(this->aa) {
for (i = 0; i < MAX_PP_AA_ARRAY; i++) { //iterate through all of the client's AAs if(!ability) {
if (this->aa[i]) { // make sure aa exists or we'll crash zone continue;
aa_AA = this->aa[i]->AA; //same as aaid from the aa_effects table
aa_value = this->aa[i]->value; //how many points in it
if (aa_AA > 0 || aa_value > 0) { //do we have the AA? if 1 of the 2 is set, we can assume we do
//slots = database.GetTotalAALevels(aa_AA); //find out how many effects from aa_effects table
slots = zone->GetTotalAALevels(aa_AA); //find out how many effects from aa_effects, which is loaded into memory
if (slots > 0) //and does it have any effects? may be able to put this above, not sure if it runs on each iteration
ApplyAABonuses(aa_AA, slots, newbon); //add the bonuses
}
}
} }
// bad data or no effects
if (rank->effects.empty())
continue;
ApplyAABonuses(*rank, newbon);
} }
} }
//A lot of the normal spell functions (IsBlankSpellEffect, etc) are set for just spells (in common/spdat.h). //A lot of the normal spell functions (IsBlankSpellEffect, etc) are set for just spells (in common/spdat.h).
//For now, we'll just put them directly into the code and comment with the corresponding normal function //For now, we'll just put them directly into the code and comment with the corresponding normal function
//Maybe we'll fix it later? :-D //Maybe we'll fix it later? :-D
void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
{ {
if(slots == 0) //sanity check. why bother if no slots to fill? if (rank.effects.empty()) // sanity check. why bother if no slots to fill?
return; return;
//from AA_Ability struct
uint32 effect = 0; uint32 effect = 0;
int32 base1 = 0; int32 base1 = 0;
int32 base2 = 0; //only really used for SE_RaiseStatCap & SE_ReduceSkillTimer in aa_effects table int32 base2 = 0; // only really used for SE_RaiseStatCap & SE_ReduceSkillTimer in aa_effects table
uint32 slot = 0; uint32 slot = 0;
std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aaid); for (const auto &e : rank.effects) {
if(find_iter == aa_effects.end()) effect = e.effect_id;
{ base1 = e.base1;
return; base2 = e.base2;
} slot = e.slot;
for (std::map<uint32, AA_Ability>::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) { // we default to 0 (SE_CurrentHP) for the effect, so if there aren't any base1/2 values, we'll just skip it
effect = iter->second.skill_id;
base1 = iter->second.base1;
base2 = iter->second.base2;
slot = iter->second.slot;
//we default to 0 (SE_CurrentHP) for the effect, so if there aren't any base1/2 values, we'll just skip it
if (effect == 0 && base1 == 0 && base2 == 0) if (effect == 0 && base1 == 0 && base2 == 0)
continue; continue;
//IsBlankSpellEffect() // IsBlankSpellEffect()
if (effect == SE_Blank || (effect == SE_CHA && base1 == 0) || effect == SE_StackingCommand_Block || effect == SE_StackingCommand_Overwrite) if (effect == SE_Blank || (effect == SE_CHA && base1 == 0) || effect == SE_StackingCommand_Block ||
effect == SE_StackingCommand_Overwrite)
continue; continue;
Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName()); Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s",
effect, rank.id, slot, base1, base2, GetCleanName());
uint8 focus = IsFocusEffect(0, 0, true,effect); uint8 focus = IsFocusEffect(0, 0, true, effect);
if (focus) if (focus) {
{
newbon->FocusEffects[focus] = static_cast<uint8>(effect); newbon->FocusEffects[focus] = static_cast<uint8>(effect);
continue; continue;
} }
switch (effect) switch (effect) {
{ // Note: AA effects that use accuracy are skill limited, while spell effect is not.
//Note: AA effects that use accuracy are skill limited, while spell effect is not.
case SE_Accuracy: case SE_Accuracy:
if ((base2 == ALL_SKILLS) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1)) // Bad data or unsupported new skill
newbon->Accuracy[HIGHEST_SKILL+1] = base1; if (base2 > HIGHEST_SKILL)
break;
if ((base2 == ALL_SKILLS) && (newbon->Accuracy[HIGHEST_SKILL + 1] < base1))
newbon->Accuracy[HIGHEST_SKILL + 1] = base1;
else if (newbon->Accuracy[base2] < base1) else if (newbon->Accuracy[base2] < base1)
newbon->Accuracy[base2] += base1; newbon->Accuracy[base2] += base1;
break; break;
case SE_CurrentHP: //regens case SE_CurrentHP: // regens
newbon->HPRegen += base1; newbon->HPRegen += base1;
break; break;
case SE_CurrentEndurance: case SE_CurrentEndurance:
newbon->EnduranceRegen += base1; newbon->EnduranceRegen += base1;
break; break;
case SE_MovementSpeed: case SE_MovementSpeed:
newbon->movementspeed += base1; //should we let these stack? newbon->movementspeed += base1; // should we let these stack?
/*if (base1 > newbon->movementspeed) //or should we use a total value? /*if (base1 > newbon->movementspeed) //or should we use a total value?
newbon->movementspeed = base1;*/ newbon->movementspeed = base1;*/
break; break;
@ -741,11 +732,14 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->CHA += base1; newbon->CHA += base1;
break; break;
case SE_WaterBreathing: case SE_WaterBreathing:
//handled by client // handled by client
break; break;
case SE_CurrentMana: case SE_CurrentMana:
newbon->ManaRegen += base1; newbon->ManaRegen += base1;
break; break;
case SE_ManaPool:
newbon->Mana += base1;
break;
case SE_ItemManaRegenCapIncrease: case SE_ItemManaRegenCapIncrease:
newbon->ItemManaRegenCap += base1; newbon->ItemManaRegenCap += base1;
break; break;
@ -782,52 +776,49 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
case SE_SetBreathLevel: case SE_SetBreathLevel:
break; break;
case SE_RaiseStatCap: case SE_RaiseStatCap:
switch(base2) switch (base2) {
{ // are these #define'd somewhere?
//are these #define'd somewhere? case 0: // str
case 0: //str
newbon->STRCapMod += base1; newbon->STRCapMod += base1;
break; break;
case 1: //sta case 1: // sta
newbon->STACapMod += base1; newbon->STACapMod += base1;
break; break;
case 2: //agi case 2: // agi
newbon->AGICapMod += base1; newbon->AGICapMod += base1;
break; break;
case 3: //dex case 3: // dex
newbon->DEXCapMod += base1; newbon->DEXCapMod += base1;
break; break;
case 4: //wis case 4: // wis
newbon->WISCapMod += base1; newbon->WISCapMod += base1;
break; break;
case 5: //int case 5: // int
newbon->INTCapMod += base1; newbon->INTCapMod += base1;
break; break;
case 6: //cha case 6: // cha
newbon->CHACapMod += base1; newbon->CHACapMod += base1;
break; break;
case 7: //mr case 7: // mr
newbon->MRCapMod += base1; newbon->MRCapMod += base1;
break; break;
case 8: //cr case 8: // cr
newbon->CRCapMod += base1; newbon->CRCapMod += base1;
break; break;
case 9: //fr case 9: // fr
newbon->FRCapMod += base1; newbon->FRCapMod += base1;
break; break;
case 10: //pr case 10: // pr
newbon->PRCapMod += base1; newbon->PRCapMod += base1;
break; break;
case 11: //dr case 11: // dr
newbon->DRCapMod += base1; newbon->DRCapMod += base1;
break; break;
case 12: //corruption case 12: // corruption
newbon->CorrupCapMod += base1; newbon->CorrupCapMod += base1;
break; break;
} }
break; break;
case SE_PetDiscipline2:
break;
case SE_SpellSlotIncrease: case SE_SpellSlotIncrease:
break; break;
case SE_MysticalAttune: case SE_MysticalAttune:
@ -939,8 +930,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->CombatStability += base1; newbon->CombatStability += base1;
break; break;
case SE_AddSingingMod: case SE_AddSingingMod:
switch (base2) switch (base2) {
{
case ItemTypeWindInstrument: case ItemTypeWindInstrument:
newbon->windMod += base1; newbon->windMod += base1;
break; break;
@ -1043,27 +1033,29 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->CrippBlowChance += base1; newbon->CrippBlowChance += base1;
break; break;
case SE_HitChance: case SE_HitChance: {
{ // Bad data or unsupported new skill
if(base2 == ALL_SKILLS) if (base2 > HIGHEST_SKILL)
newbon->HitChanceEffect[HIGHEST_SKILL+1] += base1; break;
if (base2 == ALL_SKILLS)
newbon->HitChanceEffect[HIGHEST_SKILL + 1] += base1;
else else
newbon->HitChanceEffect[base2] += base1; newbon->HitChanceEffect[base2] += base1;
} }
case SE_ProcOnKillShot: case SE_ProcOnKillShot:
for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3) for (int i = 0; i < MAX_SPELL_TRIGGER * 3; i += 3) {
{ if (!newbon->SpellOnKill[i] ||
if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i+1] < base1))) ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i + 1] < base1))) {
{ // base1 = chance, base2 = SpellID to be triggered, base3 = min npc level
//base1 = chance, base2 = SpellID to be triggered, base3 = min npc level
newbon->SpellOnKill[i] = base2; newbon->SpellOnKill[i] = base2;
newbon->SpellOnKill[i+1] = base1; newbon->SpellOnKill[i + 1] = base1;
if (GetLevel() > 15) if (GetLevel() > 15)
newbon->SpellOnKill[i+2] = GetLevel() - 15; //AA specifiy "non-trivial" newbon->SpellOnKill[i + 2] =
GetLevel() - 15; // AA specifiy "non-trivial"
else else
newbon->SpellOnKill[i+2] = 0; newbon->SpellOnKill[i + 2] = 0;
break; break;
} }
@ -1071,13 +1063,11 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
break; break;
case SE_SpellOnDeath: case SE_SpellOnDeath:
for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) for (int i = 0; i < MAX_SPELL_TRIGGER * 2; i += 2) {
{ if (!newbon->SpellOnDeath[i]) {
if(!newbon->SpellOnDeath[i])
{
// base1 = SpellID to be triggered, base2 = chance to fire // base1 = SpellID to be triggered, base2 = chance to fire
newbon->SpellOnDeath[i] = base1; newbon->SpellOnDeath[i] = base1;
newbon->SpellOnDeath[i+1] = base2; newbon->SpellOnDeath[i + 1] = base2;
break; break;
} }
} }
@ -1085,41 +1075,41 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
case SE_TriggerOnCast: case SE_TriggerOnCast:
for(int i = 0; i < MAX_SPELL_TRIGGER; i++) for (int i = 0; i < MAX_SPELL_TRIGGER; i++) {
{ if (newbon->SpellTriggers[i] == rank.id)
if (newbon->SpellTriggers[i] == aaid)
break; break;
if(!newbon->SpellTriggers[i]) if (!newbon->SpellTriggers[i]) {
{ // Save the 'rank.id' of each triggerable effect to an array
//Save the 'aaid' of each triggerable effect to an array newbon->SpellTriggers[i] = rank.id;
newbon->SpellTriggers[i] = aaid;
break; break;
} }
} }
break; break;
case SE_CriticalHitChance: case SE_CriticalHitChance: {
{ // Bad data or unsupported new skill
if(base2 == ALL_SKILLS) if (base2 > HIGHEST_SKILL)
newbon->CriticalHitChance[HIGHEST_SKILL+1] += base1; break;
if (base2 == ALL_SKILLS)
newbon->CriticalHitChance[HIGHEST_SKILL + 1] += base1;
else else
newbon->CriticalHitChance[base2] += base1; newbon->CriticalHitChance[base2] += base1;
} } break;
break;
case SE_CriticalDamageMob: case SE_CriticalDamageMob: {
{ // Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
// base1 = effect value, base2 = skill restrictions(-1 for all) // base1 = effect value, base2 = skill restrictions(-1 for all)
if(base2 == ALL_SKILLS) if (base2 == ALL_SKILLS)
newbon->CritDmgMob[HIGHEST_SKILL+1] += base1; newbon->CritDmgMob[HIGHEST_SKILL + 1] += base1;
else else
newbon->CritDmgMob[base2] += base1; newbon->CritDmgMob[base2] += base1;
break; break;
} }
case SE_CriticalSpellChance: case SE_CriticalSpellChance: {
{
newbon->CriticalSpellChance += base1; newbon->CriticalSpellChance += base1;
if (base2 > newbon->SpellCritDmgIncNoStack) if (base2 > newbon->SpellCritDmgIncNoStack)
@ -1128,72 +1118,76 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
break; break;
} }
case SE_ResistFearChance: case SE_ResistFearChance: {
{ if (base1 == 100) // If we reach 100% in a single spell/item then we should be immune to
if(base1 == 100) // If we reach 100% in a single spell/item then we should be immune to negative fear resist effects until our immunity is over // negative fear resist effects until our immunity is over
newbon->Fearless = true; newbon->Fearless = true;
newbon->ResistFearChance += base1; // these should stack newbon->ResistFearChance += base1; // these should stack
break; break;
} }
case SE_SkillDamageAmount: case SE_SkillDamageAmount: {
{ // Bad data or unsupported new skill
if(base2 == ALL_SKILLS) if (base2 > HIGHEST_SKILL)
newbon->SkillDamageAmount[HIGHEST_SKILL+1] += base1; break;
if (base2 == ALL_SKILLS)
newbon->SkillDamageAmount[HIGHEST_SKILL + 1] += base1;
else else
newbon->SkillDamageAmount[base2] += base1; newbon->SkillDamageAmount[base2] += base1;
break; break;
} }
case SE_SpecialAttackKBProc: case SE_SkillAttackProc: {
{ // You can only have one of these per client. [AA Dragon Punch]
//You can only have one of these per client. [AA Dragon Punch] newbon->SkillAttackProc[0] = base1; // Chance base 1000 = 100% proc rate
newbon->SpecialAttackKBProc[0] = base1; //Chance base 100 = 25% proc rate newbon->SkillAttackProc[1] = base2; // Skill to Proc Off
newbon->SpecialAttackKBProc[1] = base2; //Skill to KB Proc Off newbon->SkillAttackProc[2] = rank.spell; // spell to proc
break; break;
} }
case SE_DamageModifier: case SE_DamageModifier: {
{ // Bad data or unsupported new skill
if(base2 == ALL_SKILLS) if (base2 > HIGHEST_SKILL)
newbon->DamageModifier[HIGHEST_SKILL+1] += base1; break;
if (base2 == ALL_SKILLS)
newbon->DamageModifier[HIGHEST_SKILL + 1] += base1;
else else
newbon->DamageModifier[base2] += base1; newbon->DamageModifier[base2] += base1;
break; break;
} }
case SE_DamageModifier2: case SE_DamageModifier2: {
{ // Bad data or unsupported new skill
if(base2 == ALL_SKILLS) if (base2 > HIGHEST_SKILL)
newbon->DamageModifier2[HIGHEST_SKILL+1] += base1; break;
if (base2 == ALL_SKILLS)
newbon->DamageModifier2[HIGHEST_SKILL + 1] += base1;
else else
newbon->DamageModifier2[base2] += base1; newbon->DamageModifier2[base2] += base1;
break; break;
} }
case SE_SlayUndead: case SE_SlayUndead: {
{ if (newbon->SlayUndead[1] < base1)
if(newbon->SlayUndead[1] < base1)
newbon->SlayUndead[0] = base1; // Rate newbon->SlayUndead[0] = base1; // Rate
newbon->SlayUndead[1] = base2; // Damage Modifier newbon->SlayUndead[1] = base2; // Damage Modifier
break; break;
} }
case SE_DoubleRiposte: case SE_DoubleRiposte: {
{
newbon->DoubleRiposte += base1; newbon->DoubleRiposte += base1;
break;
} }
case SE_GiveDoubleRiposte: case SE_GiveDoubleRiposte: {
{ // 0=Regular Riposte 1=Skill Attack Riposte 2=Skill
//0=Regular Riposte 1=Skill Attack Riposte 2=Skill if (base2 == 0) {
if(base2 == 0){ if (newbon->GiveDoubleRiposte[0] < base1)
if(newbon->GiveDoubleRiposte[0] < base1)
newbon->GiveDoubleRiposte[0] = base1; newbon->GiveDoubleRiposte[0] = base1;
} }
//Only for special attacks. // Only for special attacks.
else if(base2 > 0 && (newbon->GiveDoubleRiposte[1] < base1)){ else if (base2 > 0 && (newbon->GiveDoubleRiposte[1] < base1)) {
newbon->GiveDoubleRiposte[1] = base1; newbon->GiveDoubleRiposte[1] = base1;
newbon->GiveDoubleRiposte[2] = base2; newbon->GiveDoubleRiposte[2] = base2;
} }
@ -1201,83 +1195,72 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
break; break;
} }
//Kayen: Not sure best way to implement this yet. // Kayen: Not sure best way to implement this yet.
//Physically raises skill cap ie if 55/55 it will raise to 55/60 // Physically raises skill cap ie if 55/55 it will raise to 55/60
case SE_RaiseSkillCap: case SE_RaiseSkillCap: {
{ if (newbon->RaiseSkillCap[0] < base1) {
if(newbon->RaiseSkillCap[0] < base1){ newbon->RaiseSkillCap[0] = base1; // value
newbon->RaiseSkillCap[0] = base1; //value newbon->RaiseSkillCap[1] = base2; // skill
newbon->RaiseSkillCap[1] = base2; //skill
} }
break; break;
} }
case SE_MasteryofPast: case SE_MasteryofPast: {
{ if (newbon->MasteryofPast < base1)
if(newbon->MasteryofPast < base1)
newbon->MasteryofPast = base1; newbon->MasteryofPast = base1;
break; break;
} }
case SE_CastingLevel2: case SE_CastingLevel2:
case SE_CastingLevel: case SE_CastingLevel: {
{
newbon->effective_casting_level += base1; newbon->effective_casting_level += base1;
break; break;
} }
case SE_DivineSave: case SE_DivineSave: {
{ if (newbon->DivineSaveChance[0] < base1) {
if(newbon->DivineSaveChance[0] < base1)
{
newbon->DivineSaveChance[0] = base1; newbon->DivineSaveChance[0] = base1;
newbon->DivineSaveChance[1] = base2; newbon->DivineSaveChance[1] = base2;
} }
break; break;
} }
case SE_SpellEffectResistChance: {
case SE_SpellEffectResistChance: for (int e = 0; e < MAX_RESISTABLE_EFFECTS * 2; e += 2) {
{ if (newbon->SEResist[e + 1] && (newbon->SEResist[e] == base2) &&
for(int e = 0; e < MAX_RESISTABLE_EFFECTS*2; e+=2) (newbon->SEResist[e + 1] < base1)) {
{ newbon->SEResist[e] = base2; // Spell Effect ID
if(newbon->SEResist[e+1] && (newbon->SEResist[e] == base2) && (newbon->SEResist[e+1] < base1)){ newbon->SEResist[e + 1] = base1; // Resist Chance
newbon->SEResist[e] = base2; //Spell Effect ID
newbon->SEResist[e+1] = base1; //Resist Chance
break; break;
} } else if (!newbon->SEResist[e + 1]) {
else if (!newbon->SEResist[e+1]){ newbon->SEResist[e] = base2; // Spell Effect ID
newbon->SEResist[e] = base2; //Spell Effect ID newbon->SEResist[e + 1] = base1; // Resist Chance
newbon->SEResist[e+1] = base1; //Resist Chance
break; break;
} }
} }
break; break;
} }
case SE_MitigateDamageShield: case SE_MitigateDamageShield: {
{
if (base1 < 0) if (base1 < 0)
base1 = base1*(-1); base1 = base1 * (-1);
newbon->DSMitigationOffHand += base1; newbon->DSMitigationOffHand += base1;
break; break;
} }
case SE_FinishingBlow: case SE_FinishingBlow: {
{ // base1 = chance, base2 = damage
//base1 = chance, base2 = damage if (newbon->FinishingBlow[1] < base2) {
if (newbon->FinishingBlow[1] < base2){
newbon->FinishingBlow[0] = base1; newbon->FinishingBlow[0] = base1;
newbon->FinishingBlow[1] = base2; newbon->FinishingBlow[1] = base2;
} }
break; break;
} }
case SE_FinishingBlowLvl: case SE_FinishingBlowLvl: {
{ // base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?)
//base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?) if (newbon->FinishingBlowLvl[0] < base1) {
if (newbon->FinishingBlowLvl[0] < base1){
newbon->FinishingBlowLvl[0] = base1; newbon->FinishingBlowLvl[0] = base1;
newbon->FinishingBlowLvl[1] = base2; newbon->FinishingBlowLvl[1] = base2;
} }
@ -1300,13 +1283,12 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->HealRate += base1; newbon->HealRate += base1;
break; break;
case SE_MeleeLifetap: case SE_MeleeLifetap: {
{
if((base1 < 0) && (newbon->MeleeLifetap > base1)) if ((base1 < 0) && (newbon->MeleeLifetap > base1))
newbon->MeleeLifetap = base1; newbon->MeleeLifetap = base1;
else if(newbon->MeleeLifetap < base1) else if (newbon->MeleeLifetap < base1)
newbon->MeleeLifetap = base1; newbon->MeleeLifetap = base1;
break; break;
} }
@ -1331,44 +1313,39 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->Metabolism += base1; newbon->Metabolism += base1;
break; break;
case SE_ImprovedReclaimEnergy: case SE_ImprovedReclaimEnergy: {
{ if ((base1 < 0) && (newbon->ImprovedReclaimEnergy > base1))
if((base1 < 0) && (newbon->ImprovedReclaimEnergy > base1))
newbon->ImprovedReclaimEnergy = base1; newbon->ImprovedReclaimEnergy = base1;
else if(newbon->ImprovedReclaimEnergy < base1) else if (newbon->ImprovedReclaimEnergy < base1)
newbon->ImprovedReclaimEnergy = base1; newbon->ImprovedReclaimEnergy = base1;
break; break;
} }
case SE_HeadShot: case SE_HeadShot: {
{ if (newbon->HeadShot[1] < base2) {
if(newbon->HeadShot[1] < base2){
newbon->HeadShot[0] = base1; newbon->HeadShot[0] = base1;
newbon->HeadShot[1] = base2; newbon->HeadShot[1] = base2;
} }
break; break;
} }
case SE_HeadShotLevel: case SE_HeadShotLevel: {
{ if (newbon->HSLevel < base1)
if(newbon->HSLevel < base1)
newbon->HSLevel = base1; newbon->HSLevel = base1;
break; break;
} }
case SE_Assassinate: case SE_Assassinate: {
{ if (newbon->Assassinate[1] < base2) {
if(newbon->Assassinate[1] < base2){
newbon->Assassinate[0] = base1; newbon->Assassinate[0] = base1;
newbon->Assassinate[1] = base2; newbon->Assassinate[1] = base2;
} }
break; break;
} }
case SE_AssassinateLevel: case SE_AssassinateLevel: {
{ if (newbon->AssassinateLevel < base1)
if(newbon->AssassinateLevel < base1)
newbon->AssassinateLevel = base1; newbon->AssassinateLevel = base1;
break; break;
} }
@ -1377,16 +1354,11 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->PetMeleeMitigation += base1; newbon->PetMeleeMitigation += base1;
break; break;
case SE_MeleeVulnerability: case SE_FactionModPct: {
newbon->MeleeVulnerability += base1; if ((base1 < 0) && (newbon->FactionModPct > base1))
break;
case SE_FactionModPct:
{
if((base1 < 0) && (newbon->FactionModPct > base1))
newbon->FactionModPct = base1; newbon->FactionModPct = base1;
else if(newbon->FactionModPct < base1) else if (newbon->FactionModPct < base1)
newbon->FactionModPct = base1; newbon->FactionModPct = base1;
break; break;
} }
@ -1395,35 +1367,36 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->IllusionPersistence = true; newbon->IllusionPersistence = true;
break; break;
case SE_LimitToSkill:{ case SE_LimitToSkill: {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if (base1 <= HIGHEST_SKILL) if (base1 <= HIGHEST_SKILL)
newbon->LimitToSkill[base1] = true; newbon->LimitToSkill[base1] = true;
break; break;
} }
case SE_SkillProc:{ case SE_SkillProc: {
for(int e = 0; e < MAX_SKILL_PROCS; e++) for (int e = 0; e < MAX_SKILL_PROCS; e++) {
{ if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id)
if(newbon->SkillProc[e] && newbon->SkillProc[e] == aaid) break; // Do not use the same aa id more than once.
break; //Do not use the same aa id more than once.
else if(!newbon->SkillProc[e]){ else if (!newbon->SkillProc[e]) {
newbon->SkillProc[e] = aaid; newbon->SkillProc[e] = rank.id;
break; break;
} }
} }
break; break;
} }
case SE_SkillProcSuccess:{ case SE_SkillProcSuccess: {
for(int e = 0; e < MAX_SKILL_PROCS; e++) for (int e = 0; e < MAX_SKILL_PROCS; e++) {
{ if (newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == rank.id)
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid) break; // Do not use the same spell id more than once.
break; //Do not use the same spell id more than once.
else if(!newbon->SkillProcSuccess[e]){ else if (!newbon->SkillProcSuccess[e]) {
newbon->SkillProcSuccess[e] = aaid; newbon->SkillProcSuccess[e] = rank.id;
break; break;
} }
} }
@ -1434,7 +1407,82 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->MeleeMitigationEffect -= base1; newbon->MeleeMitigationEffect -= base1;
break; break;
case SE_ATK:
newbon->ATK += base1;
break;
case SE_IncreaseExtTargetWindow:
newbon->extra_xtargets += base1;
break;
// to do
case SE_PetDiscipline:
break;
case SE_PetDiscipline2:
break;
case SE_ReduceTradeskillFail:
break;
case SE_PotionBeltSlots:
break;
case SE_BandolierSlots:
break;
case SE_ForageSkill:
break;
case SE_TradeSkillMastery:
break;
case SE_SecondaryForte:
break;
case SE_FeignedCastOnChance:
break;
case SE_ExtendedShielding:
break;
case SE_ShieldDuration:
break;
case SE_ReduceApplyPoisonTime:
break;
case SE_NimbleEvasion:
break;
case SE_TrapCircumvention:
break;
case SE_ShroudofStealth:
break;
case SE_FeignedMinion:
break;
// handled client side
case SE_ReduceFallDamage:
// not handled here
case SE_HastenedAASkill:
// not handled here but don't want to clutter debug log -- these may need to be verified to ignore
case SE_LimitMaxLevel:
case SE_LimitResist:
case SE_LimitTarget:
case SE_LimitEffect:
case SE_LimitSpellType:
case SE_LimitMinDur:
case SE_LimitInstant:
case SE_LimitMinLevel:
case SE_LimitCastTimeMin:
case SE_LimitCastTimeMax:
case SE_LimitSpell:
case SE_LimitCombatSkills:
case SE_LimitManaMin:
case SE_LimitSpellGroup:
case SE_LimitSpellClass:
case SE_LimitSpellSubclass:
case SE_LimitHPPercent:
case SE_LimitManaPercent:
case SE_LimitEndPercent:
case SE_LimitClass:
case SE_LimitRace:
case SE_LimitCastingSkill:
case SE_LimitUseMin:
case SE_LimitUseType:
break;
default:
Log.Out(Logs::Detail, Logs::AA, "SPA %d not accounted for in AA %s (%d)", effect, rank.base_ability->name.c_str(), rank.id);
break;
} }
} }
} }
@ -1875,6 +1923,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_CriticalHitChance: case SE_CriticalHitChance:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if (AdditiveWornBonus) { if (AdditiveWornBonus) {
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value; new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value;
@ -2078,6 +2129,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_HitChance: case SE_HitChance:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if (AdditiveWornBonus){ if (AdditiveWornBonus){
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
@ -2112,6 +2166,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_DamageModifier: case SE_DamageModifier:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value; new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value;
else else
@ -2121,6 +2178,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_DamageModifier2: case SE_DamageModifier2:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value; new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value;
else else
@ -2130,6 +2190,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_MinDamageModifier: case SE_MinDamageModifier:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value; new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value;
else else
@ -2203,6 +2266,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_Accuracy: case SE_Accuracy:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if ((effect_value < 0) && (new_bonus->Accuracy[HIGHEST_SKILL+1] > effect_value)) if ((effect_value < 0) && (new_bonus->Accuracy[HIGHEST_SKILL+1] > effect_value))
new_bonus->Accuracy[HIGHEST_SKILL+1] = effect_value; new_bonus->Accuracy[HIGHEST_SKILL+1] = effect_value;
@ -2226,6 +2292,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_SkillDamageTaken: case SE_SkillDamageTaken:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
//When using npc_spells_effects if MAX value set, use stackable quest based modifier. //When using npc_spells_effects if MAX value set, use stackable quest based modifier.
if (IsAISpellEffect && max){ if (IsAISpellEffect && max){
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
@ -2344,6 +2413,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_CriticalDamageMob: case SE_CriticalDamageMob:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value; new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value;
else else
@ -2360,6 +2432,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_SkillDamageAmount: case SE_SkillDamageAmount:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value; new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value;
else else
@ -2465,6 +2540,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_SkillDamageAmount2: case SE_SkillDamageAmount2:
{ {
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if(base2 == ALL_SKILLS) if(base2 == ALL_SKILLS)
new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value; new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value;
else else
@ -2980,10 +3058,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
new_bonus->PetMeleeMitigation += effect_value; new_bonus->PetMeleeMitigation += effect_value;
break; break;
case SE_MeleeVulnerability:
new_bonus->MeleeVulnerability += effect_value;
break;
case SE_Sanctuary: case SE_Sanctuary:
new_bonus->Sanctuary = true; new_bonus->Sanctuary = true;
break; break;
@ -3003,6 +3077,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break; break;
case SE_LimitToSkill:{ case SE_LimitToSkill:{
// Bad data or unsupported new skill
if (base2 > HIGHEST_SKILL)
break;
if (effect_value <= HIGHEST_SKILL){ if (effect_value <= HIGHEST_SKILL){
new_bonus->LimitToSkill[effect_value] = true; new_bonus->LimitToSkill[effect_value] = true;
} }
@ -4560,12 +4637,6 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
aabonuses.FactionModPct = effect_value; aabonuses.FactionModPct = effect_value;
break; break;
case SE_MeleeVulnerability:
spellbonuses.MeleeVulnerability = effect_value;
itembonuses.MeleeVulnerability = effect_value;
aabonuses.MeleeVulnerability = effect_value;
break;
case SE_IllusionPersistence: case SE_IllusionPersistence:
spellbonuses.IllusionPersistence = false; spellbonuses.IllusionPersistence = false;
itembonuses.IllusionPersistence = false; itembonuses.IllusionPersistence = false;

View File

@ -1259,601 +1259,40 @@ int32 Bot::GenerateBaseHitPoints() {
return new_base_hp; return new_base_hp;
} }
void Bot::GenerateAABonuses(StatBonuses* newbon) {
// General AA bonus
uint8 botClass = GetClass();
uint8 botLevel = GetLevel();
memset(newbon, 0, sizeof(StatBonuses)); //start fresh
if(botLevel >= 51) {
//level 51 = 1 AA level
int i;
int totalAAs = database.CountAAs();
uint32 slots = 0;
uint32 aa_AA = 0;
uint32 aa_value = 0;
for (i = 0; i < totalAAs; i++) { //iterate through all of the client's AAs
std::map<uint32, BotAA>::iterator aa = botAAs.find(i);
if(aa != botAAs.end()) { // make sure aa exists or we'll crash zone
aa_AA = aa->second.aa_id; //same as aaid from the aa_effects table
aa_value = aa->second.total_levels; //how many points in it
if (aa_AA > 0 || aa_value > 0) { //do we have the AA? if 1 of the 2 is set, we can assume we do
//slots = database.GetTotalAALevels(aa_AA); //find out how many effects from aa_effects table
slots = zone->GetTotalAALevels(aa_AA); //find out how many effects from aa_effects, which is loaded into memory
if (slots > 0) //and does it have any effects? may be able to put this above, not sure if it runs on each iteration
ApplyAABonuses((aa_AA + aa_value - 1), slots, newbon); //add the bonuses
}
}
}
}
}
void Bot::LoadAAs() { void Bot::LoadAAs() {
int maxAAExpansion = RuleI(Bots, BotAAExpansion); //get expansion to get AAs up to int maxAAExpansion = RuleI(Bots, BotAAExpansion); //get expansion to get AAs up to
botAAs.clear(); //start fresh aa_ranks.clear();
std::string query; int id = 0;
if(GetClass() == BERSERKER) int points = 0;
query = StringFormat("SELECT skill_id FROM altadv_vars WHERE berserker = 1 AND class_type > 1 AND class_type <= %i AND aa_expansion <= %i ORDER BY skill_id;", GetLevel(), maxAAExpansion); auto iter = zone->aa_abilities.begin();
else while(iter != zone->aa_abilities.end()) {
query = StringFormat("SELECT skill_id FROM altadv_vars WHERE ((classes & ( 1 << %i )) >> %i) = 1 AND class_type > 1 AND class_type <= %i AND aa_expansion <= %i ORDER BY skill_id;", GetClass(), GetClass(), GetLevel(), maxAAExpansion); AA::Ability *ability = (*iter).second.get();
auto results = database.QueryDatabase(query); //skip expendables
if(!results.Success()) { if(!ability->first || ability->charges > 0) {
Log.Out(Logs::General, Logs::Error, "Error in Bot::LoadAAs()");
return;
}
int totalAAs = database.CountAAs();
for (auto row = results.begin(); row != results.end(); ++row) {
uint32 skill_id = 0;
skill_id = atoi(row[0]);
if(skill_id <= 0 || skill_id >= totalAAs)
continue;
SendAA_Struct *sendAA = zone->FindAA(skill_id);
if(!sendAA)
continue;
for(int i=0; i<sendAA->max_level; i++) {
//Get AA info & add to list
uint32 aaid = (sendAA->id + i);
uint8 total_levels = 0;
uint8 req_level;
std::map<uint32, AALevelCost_Struct>::iterator RequiredLevel = AARequiredLevelAndCost.find(aaid);
//Get level required for AA
if(RequiredLevel != AARequiredLevelAndCost.end())
req_level = RequiredLevel->second.Level;
else
req_level = (sendAA->class_type + i * sendAA->level_inc);
if(req_level > GetLevel())
break;
//Bot is high enough level for AA
std::map<uint32, BotAA>::iterator foundAA = botAAs.find(aaid);
// AA is already in list
if(foundAA != botAAs.end())
continue;
if(sendAA->id == aaid) {
BotAA newAA;
newAA.total_levels = 0;
newAA.aa_id = aaid;
newAA.req_level = req_level;
newAA.total_levels += 1;
botAAs[aaid] = newAA; //add to list
}
else //update master AA record with number of levels a bot has in AA, based on level.
botAAs[sendAA->id].total_levels += 1;
}
}
}
uint32 Bot::GetAA(uint32 aa_id) {
std::map<uint32, BotAA >::const_iterator find_iter = botAAs.find(aa_id);
int aaLevel = 0;
if(find_iter != botAAs.end())
aaLevel = find_iter->second.total_levels;
return aaLevel;
}
//current with Client::ApplyAABonuses 9/26/12
void Bot::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) {
if(slots == 0) //sanity check. why bother if no slots to fill?
return;
//from AA_Ability struct
uint32 effect = 0;
int32 base1 = 0;
int32 base2 = 0; //only really used for SE_RaiseStatCap & SE_ReduceSkillTimer in aa_effects table
uint32 slot = 0;
std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aaid);
if(find_iter == aa_effects.end())
return;
for (std::map<uint32, AA_Ability>::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) {
effect = iter->second.skill_id;
base1 = iter->second.base1;
base2 = iter->second.base2;
slot = iter->second.slot;
//we default to 0 (SE_CurrentHP) for the effect, so if there aren't any base1/2 values, we'll just skip it
if ((effect == 0 && base1 == 0 && base2 == 0) || effect == SE_Blank || (effect == SE_CHA && base1 == 0) || effect == SE_StackingCommand_Block || effect == SE_StackingCommand_Overwrite)
continue;
Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName());
uint8 focus = IsFocusEffect(0, 0, true, effect);
if (focus) {
newbon->FocusEffects[focus] = effect;
continue; continue;
} }
switch (effect) { id = ability->first->id;
//Note: AA effects that use accuracy are skill limited, while spell effect is not. points = 0;
case SE_Accuracy:
if ((base2 == -1) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1))
newbon->Accuracy[HIGHEST_SKILL+1] = base1;
else if (newbon->Accuracy[base2] < base1)
newbon->Accuracy[base2] += base1;
break;
case SE_CurrentHP: //regens
newbon->HPRegen += base1;
break;
case SE_CurrentEndurance:
newbon->EnduranceRegen += base1;
break;
case SE_MovementSpeed:
newbon->movementspeed += base1;
break;
case SE_STR:
newbon->STR += base1;
break;
case SE_DEX:
newbon->DEX += base1;
break;
case SE_AGI:
newbon->AGI += base1;
break;
case SE_STA:
newbon->STA += base1;
break;
case SE_INT:
newbon->INT += base1;
break;
case SE_WIS:
newbon->WIS += base1;
break;
case SE_CHA:
newbon->CHA += base1;
break;
case SE_WaterBreathing:
//handled by client
break;
case SE_CurrentMana:
newbon->ManaRegen += base1;
break;
case SE_ItemManaRegenCapIncrease:
newbon->ItemManaRegenCap += base1;
break;
case SE_ResistFire:
newbon->FR += base1;
break;
case SE_ResistCold:
newbon->CR += base1;
break;
case SE_ResistPoison:
newbon->PR += base1;
break;
case SE_ResistDisease:
newbon->DR += base1;
break;
case SE_ResistMagic:
newbon->MR += base1;
break;
case SE_ResistCorruption:
newbon->Corrup += base1;
break;
case SE_IncreaseSpellHaste:
break;
case SE_IncreaseRange:
break;
case SE_MaxHPChange:
newbon->MaxHP += base1;
break;
case SE_Packrat:
newbon->Packrat += base1;
break;
case SE_TwoHandBash:
break;
case SE_SetBreathLevel:
break;
case SE_RaiseStatCap:
switch(base2) {
//are these #define'd somewhere?
case 0: //str
newbon->STRCapMod += base1;
break;
case 1: //sta
newbon->STACapMod += base1;
break;
case 2: //agi
newbon->AGICapMod += base1;
break;
case 3: //dex
newbon->DEXCapMod += base1;
break;
case 4: //wis
newbon->WISCapMod += base1;
break;
case 5: //int
newbon->INTCapMod += base1;
break;
case 6: //cha
newbon->CHACapMod += base1;
break;
case 7: //mr
newbon->MRCapMod += base1;
break;
case 8: //cr
newbon->CRCapMod += base1;
break;
case 9: //fr
newbon->FRCapMod += base1;
break;
case 10: //pr
newbon->PRCapMod += base1;
break;
case 11: //dr
newbon->DRCapMod += base1;
break;
case 12: //corruption
newbon->CorrupCapMod += base1;
break;
}
break;
case SE_PetDiscipline2:
break;
case SE_SpellSlotIncrease:
break;
case SE_MysticalAttune:
newbon->BuffSlotIncrease += base1;
break;
case SE_TotalHP:
newbon->HP += base1;
break;
case SE_StunResist:
newbon->StunResist += base1;
break;
case SE_SpellCritChance:
newbon->CriticalSpellChance += base1;
break;
case SE_SpellCritDmgIncrease:
newbon->SpellCritDmgIncrease += base1;
break;
case SE_DotCritDmgIncrease:
newbon->DotCritDmgIncrease += base1;
break;
case SE_ResistSpellChance:
newbon->ResistSpellChance += base1;
break;
case SE_CriticalHealChance:
newbon->CriticalHealChance += base1;
break;
case SE_CriticalHealOverTime:
newbon->CriticalHealOverTime += base1;
break;
case SE_CriticalDoTChance:
newbon->CriticalDoTChance += base1;
break;
case SE_ReduceSkillTimer:
newbon->SkillReuseTime[base2] += base1;
break;
case SE_Fearless:
newbon->Fearless = true;
break;
case SE_PersistantCasting:
newbon->PersistantCasting += base1;
break;
case SE_DelayDeath:
newbon->DelayDeath += base1;
break;
case SE_FrontalStunResist:
newbon->FrontalStunResist += base1;
break;
case SE_ImprovedBindWound:
newbon->BindWound += base1;
break;
case SE_MaxBindWound:
newbon->MaxBindWound += base1;
break;
case SE_ExtraAttackChance:
newbon->ExtraAttackChance += base1;
break;
case SE_SeeInvis:
newbon->SeeInvis = base1;
break;
case SE_BaseMovementSpeed:
newbon->BaseMovementSpeed += base1;
break;
case SE_IncreaseRunSpeedCap:
newbon->IncreaseRunSpeedCap += base1;
break;
case SE_ConsumeProjectile:
newbon->ConsumeProjectile += base1;
break;
case SE_ArcheryDamageModifier:
newbon->ArcheryDamageModifier += base1;
break;
case SE_DamageShield:
newbon->DamageShield += base1;
break;
case SE_CharmBreakChance:
newbon->CharmBreakChance += base1;
break;
case SE_OffhandRiposteFail:
newbon->OffhandRiposteFail += base1;
break;
case SE_ItemAttackCapIncrease:
newbon->ItemATKCap += base1;
break;
case SE_GivePetGroupTarget:
newbon->GivePetGroupTarget = true;
break;
case SE_ItemHPRegenCapIncrease:
newbon->ItemHPRegenCap = +base1;
break;
case SE_Ambidexterity:
newbon->Ambidexterity += base1;
break;
case SE_PetMaxHP:
newbon->PetMaxHP += base1;
break;
case SE_AvoidMeleeChance:
newbon->AvoidMeleeChance += base1;
break;
case SE_CombatStability:
newbon->CombatStability += base1;
break;
case SE_PetCriticalHit:
newbon->PetCriticalHit += base1;
break;
case SE_PetAvoidance:
newbon->PetAvoidance += base1;
break;
case SE_ShieldBlock:
newbon->ShieldBlock += base1;
break;
case SE_SecondaryDmgInc:
newbon->SecondaryDmgInc = true;
break;
case SE_ChangeAggro:
newbon->hatemod += base1;
break;
case SE_EndurancePool:
newbon->Endurance += base1;
break;
case SE_ChannelChanceItems:
newbon->ChannelChanceItems += base1;
break;
case SE_ChannelChanceSpells:
newbon->ChannelChanceSpells += base1;
break;
case SE_DoubleSpecialAttack:
newbon->DoubleSpecialAttack += base1;
break;
case SE_TripleBackstab:
newbon->TripleBackstab += base1;
break;
case SE_FrontalBackstabMinDmg:
newbon->FrontalBackstabMinDmg = true;
break;
case SE_FrontalBackstabChance:
newbon->FrontalBackstabChance += base1;
break;
case SE_BlockBehind:
newbon->BlockBehind += base1;
break;
case SE_StrikeThrough2:
newbon->StrikeThrough += base1;
break;
case SE_DoubleAttackChance:
newbon->DoubleAttackChance += base1;
break;
case SE_GiveDoubleAttack:
newbon->GiveDoubleAttack += base1;
break;
case SE_ProcChance:
newbon->ProcChance += base1;
break;
case SE_RiposteChance:
newbon->RiposteChance += base1;
break;
case SE_Flurry:
newbon->FlurryChance += base1;
break;
case SE_PetFlurry:
newbon->PetFlurry = base1;
break;
case SE_BardSongRange:
newbon->SongRange += base1;
break;
case SE_RootBreakChance:
newbon->RootBreakChance += base1;
break;
case SE_UnfailingDivinity:
newbon->UnfailingDivinity += base1;
break;
case SE_ProcOnKillShot: {
for(int i = 0; i < (MAX_SPELL_TRIGGER * 3); i += 3) {
if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i + 1] < base1))) {
//base1 = chance, base2 = SpellID to be triggered, base3 = min npc level
newbon->SpellOnKill[i] = base2;
newbon->SpellOnKill[i + 1] = base1;
if (GetLevel() > 15) AA::Rank *current = ability->first;
newbon->SpellOnKill[i + 2] = (GetLevel() - 15); //AA specifiy "non-trivial"
else
newbon->SpellOnKill[i + 2] = 0;
break; while(current) {
if(!CanUseAlternateAdvancementRank(current)) {
current = nullptr;
} else {
current = current->next;
points++;
} }
} }
break;
}
case SE_SpellOnDeath: {
for(int i = 0; i < (MAX_SPELL_TRIGGER * 2); i += 2) {
if(!newbon->SpellOnDeath[i]) {
// base1 = SpellID to be triggered, base2 = chance to fire
newbon->SpellOnDeath[i] = base1;
newbon->SpellOnDeath[i + 1] = base2;
break;
}
}
break;
}
case SE_TriggerOnCast: {
for(int i = 0; i < MAX_SPELL_TRIGGER; i++) {
if (newbon->SpellTriggers[i] == aaid)
break;
if(!newbon->SpellTriggers[i]) { if(points > 0) {
//Save the 'aaid' of each triggerable effect to an array SetAA(id, points);
newbon->SpellTriggers[i] = aaid;
break;
} }
}
break;
}
case SE_CriticalHitChance: {
if(base2 == -1)
newbon->CriticalHitChance[HIGHEST_SKILL+1] += base1;
else
newbon->CriticalHitChance[base2] += base1;
break;
}
case SE_CriticalDamageMob: {
// base1 = effect value, base2 = skill restrictions(-1 for all)
if(base2 == -1)
newbon->CritDmgMob[HIGHEST_SKILL + 1] += base1;
else
newbon->CritDmgMob[base2] += base1;
break;
}
case SE_CriticalSpellChance: {
newbon->CriticalSpellChance += base1;
if (base2 > newbon->SpellCritDmgIncrease)
newbon->SpellCritDmgIncrease = base2;
break; ++iter;
}
case SE_ResistFearChance: {
if(base1 == 100) // If we reach 100% in a single spell/item then we should be immune to negative fear resist effects until our immunity is over
newbon->Fearless = true;
newbon->ResistFearChance += base1; // these should stack
break;
}
case SE_SkillDamageAmount: {
if(base2 == -1)
newbon->SkillDamageAmount[HIGHEST_SKILL + 1] += base1;
else
newbon->SkillDamageAmount[base2] += base1;
break;
}
case SE_SpecialAttackKBProc: {
//You can only have one of these per client. [AA Dragon Punch]
newbon->SpecialAttackKBProc[0] = base1; //Chance base 100 = 25% proc rate
newbon->SpecialAttackKBProc[1] = base2; //Skill to KB Proc Off
break;
}
case SE_DamageModifier: {
if(base2 == -1)
newbon->DamageModifier[HIGHEST_SKILL + 1] += base1;
else
newbon->DamageModifier[base2] += base1;
break;
}
case SE_SlayUndead: {
if(newbon->SlayUndead[1] < base1)
newbon->SlayUndead[0] = base1; // Rate
newbon->SlayUndead[1] = base2; // Damage Modifier
break;
}
case SE_GiveDoubleRiposte: {
//0=Regular Riposte 1=Skill Attack Riposte 2=Skill
if(base2 == 0) {
if(newbon->GiveDoubleRiposte[0] < base1)
newbon->GiveDoubleRiposte[0] = base1;
}
//Only for special attacks.
else if(base2 > 0 && (newbon->GiveDoubleRiposte[1] < base1)) {
newbon->GiveDoubleRiposte[1] = base1;
newbon->GiveDoubleRiposte[2] = base2;
}
break;
}
//Kayen: Not sure best way to implement this yet.
//Physically raises skill cap ie if 55/55 it will raise to 55/60
case SE_RaiseSkillCap: {
if(newbon->RaiseSkillCap[0] < base1) {
newbon->RaiseSkillCap[0] = base1; //value
newbon->RaiseSkillCap[1] = base2; //skill
}
break;
}
case SE_MasteryofPast: {
if(newbon->MasteryofPast < base1)
newbon->MasteryofPast = base1;
break;
}
case SE_CastingLevel2:
case SE_CastingLevel: {
newbon->effective_casting_level += base1;
break;
}
case SE_DivineSave: {
if(newbon->DivineSaveChance[0] < base1) {
newbon->DivineSaveChance[0] = base1;
newbon->DivineSaveChance[1] = base2;
}
break;
}
case SE_SpellEffectResistChance: {
for(int e = 0; e < (MAX_RESISTABLE_EFFECTS * 2); e += 2) {
if(!newbon->SEResist[e] || ((newbon->SEResist[e] = base2) && (newbon->SEResist[e + 1] < base1)) ){
newbon->SEResist[e] = base2;
newbon->SEResist[e + 1] = base1;
break;
}
}
break;
}
case SE_MitigateDamageShield: {
if (base1 < 0)
base1 = (base1 * -1);
newbon->DSMitigationOffHand += base1;
break;
}
case SE_FinishingBlow: {
//base1 = chance, base2 = damage
if (newbon->FinishingBlow[1] < base2) {
newbon->FinishingBlow[0] = base1;
newbon->FinishingBlow[1] = base2;
}
break;
}
case SE_FinishingBlowLvl: {
//base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?)
if (newbon->FinishingBlowLvl[0] < base1) {
newbon->FinishingBlowLvl[0] = base1;
newbon->FinishingBlowLvl[1] = base2;
}
break;
}
}
} }
} }
@ -5495,7 +4934,8 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
return false; return false;
} }
int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) { int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 spell_id)
{
const SPDat_Spell_Struct &spell = spells[spell_id]; const SPDat_Spell_Struct &spell = spells[spell_id];
int32 value = 0; int32 value = 0;
int lvlModifier = 100; int lvlModifier = 100;
@ -5509,15 +4949,21 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) {
uint32 slot = 0; uint32 slot = 0;
bool LimitFound = false; bool LimitFound = false;
int FocusCount = 0; int FocusCount = 0;
std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aa_ID);
if(find_iter == aa_effects.end())
return 0;
for (std::map<uint32, AA_Ability>::const_iterator iter = aa_effects[aa_ID].begin(); iter != aa_effects[aa_ID].end(); ++iter) { auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa_ID, points);
effect = iter->second.skill_id; auto ability = ability_rank.first;
base1 = iter->second.base1; auto rank = ability_rank.second;
base2 = iter->second.base2;
slot = iter->second.slot; if(!ability) {
return 0;
}
for(auto &eff : rank->effects) {
effect = eff.effect_id;
base1 = eff.base1;
base2 = eff.base2;
slot = eff.slot;
//AA Foci's can contain multiple focus effects within the same AA. //AA Foci's can contain multiple focus effects within the same AA.
//To handle this we will not automatically return zero if a limit is found. //To handle this we will not automatically return zero if a limit is found.
//Instead if limit is found and multiple effects, we will reset the limit check //Instead if limit is found and multiple effects, we will reset the limit check
@ -5731,6 +5177,24 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) {
value = base1; value = base1;
break; break;
} }
/*
case SE_SympatheticProc:
{
if(type == focusSympatheticProc)
{
float ProcChance, ProcBonus;
int16 ProcRateMod = base1; //Baseline is 100 for most Sympathetic foci
int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time);
GetSympatheticProcChances(ProcBonus, ProcChance, cast_time, ProcRateMod);
if(zone->random.Real(0, 1) <= ProcChance)
value = focus_id;
else
value = 0;
}
break;
}*/
case SE_FcDamageAmt: { case SE_FcDamageAmt: {
if(type == focusFcDamageAmt) if(type == focusFcDamageAmt)
value = base1; value = base1;
@ -5915,21 +5379,30 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) {
// AA Focus // AA Focus
if (aabonuses.FocusEffects[bottype]) { if (aabonuses.FocusEffects[bottype]) {
int totalAAs = database.CountAAs();
int32 Total3 = 0; int32 Total3 = 0;
uint32 slots = 0; uint32 slots = 0;
uint32 aa_AA = 0; uint32 aa_AA = 0;
uint32 aa_value = 0; uint32 aa_value = 0;
for (int i = 0; i < totalAAs; i++) { //iterate through all of the client's AAs
std::map<uint32, BotAA>::iterator aa = botAAs.find(i); for(auto &aa : aa_ranks) {
if(aa != botAAs.end()) { // make sure aa exists or we'll crash zone auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
aa_AA = aa->second.aa_id; //same as aaid from the aa_effects table auto ability = ability_rank.first;
aa_value = aa->second.total_levels; //how many points in it auto rank = ability_rank.second;
if(!ability) {
continue;
}
aa_AA = ability->id;
aa_value = aa.second.first;
if (aa_AA < 1 || aa_value < 1) if (aa_AA < 1 || aa_value < 1)
continue; continue;
Total3 = CalcBotAAFocus(bottype, aa_AA, spell_id); Total3 = CalcBotAAFocus(bottype, aa_AA, aa_value, spell_id);
if ((Total3 > 0 && realTotal3 >= 0 && Total3 > realTotal3) || (Total3 < 0 && Total3 < realTotal3)) if (Total3 > 0 && realTotal3 >= 0 && Total3 > realTotal3) {
realTotal3 = Total3;
}
else if (Total3 < 0 && Total3 < realTotal3) {
realTotal3 = Total3; realTotal3 = Total3;
} }
} }
@ -6540,13 +6013,15 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if (max_damage > 0) if (max_damage > 0)
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess); CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
/* if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){
int kb_chance = 25; int kb_chance = 25;
kb_chance += (kb_chance * (100 - aabonuses.SpecialAttackKBProc[0]) / 100); kb_chance += (kb_chance * (100 - aabonuses.SpecialAttackKBProc[0]) / 100);
if (zone->random.Int(0, 99) < kb_chance) if (zone->random.Int(0, 99) < kb_chance)
SpellFinished(904, who, 10, 0, -1, spells[904].ResistDiff); SpellFinished(904, who, 10, 0, -1, spells[904].ResistDiff);
} //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC.
}*/
if (HasSkillProcs()) if (HasSkillProcs())
TrySkillProc(who, skill, (ReuseTime * 1000)); TrySkillProc(who, skill, (ReuseTime * 1000));
@ -7556,7 +7031,8 @@ void Bot::DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster) {
Mob::DoBuffTic(buff, slot, caster); Mob::DoBuffTic(buff, slot, caster);
} }
bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust) { bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost,
uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust, uint32 aa_id) {
bool Result = false; bool Result = false;
if(zone && !zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) { if(zone && !zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) {
Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d", spells[spell_id].name, spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot); Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d", spells[spell_id].name, spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot);
@ -7612,7 +7088,8 @@ bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_t
bardsong_slot = 0; bardsong_slot = 0;
bardsong_timer.Disable(); bardsong_timer.Disable();
} }
Result = DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot);
Result = DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, aa_id);
} }
return Result; return Result;
} }
@ -7751,12 +7228,13 @@ bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
return Result; return Result;
} }
bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot) { bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, uint32 aa_id) {
bool Result = false; bool Result = false;
if(GetClass() == BARD) if(GetClass() == BARD)
cast_time = 0; cast_time = 0;
Result = Mob::DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot); Result = Mob::DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, aa_id);
if(oSpellWillFinish) { if(oSpellWillFinish) {
const SPDat_Spell_Struct &spell = spells[spell_id]; const SPDat_Spell_Struct &spell = spells[spell_id];
*oSpellWillFinish = Timer::GetCurrentTime() + ((spell.recast_time > 20000) ? 10000 : spell.recast_time); *oSpellWillFinish = Timer::GetCurrentTime() + ((spell.recast_time > 20000) ? 10000 : spell.recast_time);
@ -7941,7 +7419,7 @@ void Bot::CalcBonuses() {
GenerateBaseStats(); GenerateBaseStats();
CalcItemBonuses(&itembonuses); CalcItemBonuses(&itembonuses);
CalcSpellBonuses(&spellbonuses); CalcSpellBonuses(&spellbonuses);
GenerateAABonuses(&aabonuses); CalcAABonuses(&aabonuses);
SetAttackTimer(); SetAttackTimer();
CalcATK(); CalcATK();
CalcSTR(); CalcSTR();

View File

@ -314,11 +314,12 @@ public:
virtual float GetAOERange(uint16 spell_id); virtual float GetAOERange(uint16 spell_id);
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100); virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr); virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr); virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0,
uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr, uint32 aa_id = 0);
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar); virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction); virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction);
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF); virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0);
// Bot Action Command Methods // Bot Action Command Methods
bool MesmerizeTarget(Mob* target); bool MesmerizeTarget(Mob* target);
@ -448,9 +449,6 @@ public:
bool IsBotWISCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN); } bool IsBotWISCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN); }
bool CanHeal(); bool CanHeal();
int GetRawACNoShield(int &shield_ac); int GetRawACNoShield(int &shield_ac);
void LoadAAs();
uint32 GetAA(uint32 aa_id);
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
bool GetHasBeenSummoned() { return _hasBeenSummoned; } bool GetHasBeenSummoned() { return _hasBeenSummoned; }
const glm::vec3 GetPreSummonLocation() const { return m_PreSummonLocation; } const glm::vec3 GetPreSummonLocation() const { return m_PreSummonLocation; }
bool GetGroupMessagesOn() { return _groupMessagesOn; } bool GetGroupMessagesOn() { return _groupMessagesOn; }
@ -564,7 +562,7 @@ protected:
virtual bool CheckBotDoubleAttack(bool Triple = false); virtual bool CheckBotDoubleAttack(bool Triple = false);
virtual int32 GetBotFocusEffect(BotfocusType bottype, uint16 spell_id); virtual int32 GetBotFocusEffect(BotfocusType bottype, uint16 spell_id);
virtual int32 CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false); virtual int32 CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false);
virtual int32 CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id); virtual int32 CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 spell_id);
virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client); virtual void PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client);
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
virtual float GetMaxMeleeRangeToTarget(Mob* target); virtual float GetMaxMeleeRangeToTarget(Mob* target);
@ -646,12 +644,12 @@ private:
uint8 _baseGender; // Bots gender. Necessary to preserve the original value otherwise it can be changed by illusions. uint8 _baseGender; // Bots gender. Necessary to preserve the original value otherwise it can be changed by illusions.
// Class Methods // Class Methods
void LoadAAs();
int32 acmod(); int32 acmod();
void GenerateBaseStats(); void GenerateBaseStats();
void GenerateAppearance(); void GenerateAppearance();
void GenerateArmorClass(); void GenerateArmorClass();
int32 GenerateBaseHitPoints(); int32 GenerateBaseHitPoints();
void GenerateAABonuses(StatBonuses* newbon);
int32 GenerateBaseManaPoints(); int32 GenerateBaseManaPoints();
void GenerateSpecialAttacks(); void GenerateSpecialAttacks();
void SetBotID(uint32 botID); void SetBotID(uint32 botID);

View File

@ -176,7 +176,6 @@ Client::Client(EQStreamInterface* ieqs)
admin = 0; admin = 0;
lsaccountid = 0; lsaccountid = 0;
shield_target = nullptr; shield_target = nullptr;
SQL_log = nullptr;
guild_id = GUILD_NONE; guild_id = GUILD_NONE;
guildrank = 0; guildrank = 0;
GuildBanker = false; GuildBanker = false;
@ -441,7 +440,7 @@ void Client::SendZoneInPackets()
//Send AA Exp packet: //Send AA Exp packet:
if (GetLevel() >= 51) if (GetLevel() >= 51)
SendAAStats(); SendAlternateAdvancementStats();
// Send exp packets // Send exp packets
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
@ -458,7 +457,7 @@ void Client::SendZoneInPackets()
} }
safe_delete(outapp); safe_delete(outapp);
SendAATimers(); SendAlternateAdvancementTimers();
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct)); outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer; ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
@ -525,48 +524,39 @@ void Client::ReportConnectingState() {
}; };
} }
bool Client::SaveAA(){ bool Client::SaveAA() {
int first_entry = 0; std::string iquery;
std::string rquery;
/* Save Player AA */
int spentpoints = 0; int spentpoints = 0;
for (int a = 0; a < MAX_PP_AA_ARRAY; a++) { int i = 0;
uint32 points = aa[a]->value; for(auto &rank : aa_ranks) {
if (points > HIGHEST_AA_VALUE) { AA::Ability *ability = zone->GetAlternateAdvancementAbility(rank.first);
aa[a]->value = HIGHEST_AA_VALUE; if(!ability)
points = HIGHEST_AA_VALUE; continue;
}
if (points > 0) { if(rank.second.first > 0) {
SendAA_Struct* curAA = zone->FindAA(aa[a]->AA - aa[a]->value + 1); AA::Rank *r = ability->GetRankByPointsSpent(rank.second.first);
if (curAA) {
for (int rank = 0; rank<points; rank++) { if(!r)
std::map<uint32, AALevelCost_Struct>::iterator RequiredLevel = AARequiredLevelAndCost.find(aa[a]->AA - aa[a]->value + 1 + rank); continue;
if (RequiredLevel != AARequiredLevelAndCost.end()) {
spentpoints += RequiredLevel->second.Cost; spentpoints += r->total_cost;
}
else if(i == 0) {
spentpoints += (curAA->cost + (curAA->cost_inc * rank)); 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);
}
}
}
m_pp.aapoints_spent = spentpoints + m_epp.expended_aa;
int highest = 0;
for (int a = 0; a < MAX_PP_AA_ARRAY; a++) {
if (aa[a]->AA > 0) { // those with value 0 will be cleaned up on next load
if (first_entry != 1){
rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value, charges)"
" VALUES (%u, %u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value, aa[a]->charges);
first_entry = 1;
} else { } else {
rquery = rquery + StringFormat(", (%u, %u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value, aa[a]->charges); iquery += StringFormat(", (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second);
} }
highest = a; i++;
} }
} }
auto results = database.QueryDatabase(rquery);
/* This is another part of the hack to clean up holes left by expendable AAs */ m_pp.aapoints_spent = spentpoints + m_epp.expended_aa;
rquery = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u AND `slot` > %d", character_id, highest);
if(iquery.length() > 0) {
database.QueryDatabase(iquery);
}
return true; return true;
} }
@ -8041,56 +8031,6 @@ void Client::TryItemTimer(int slot)
} }
} }
void Client::RefundAA() {
int cur = 0;
bool refunded = false;
for(int x = 0; x < aaHighestID; x++) {
cur = GetAA(x);
if(cur > 0){
SendAA_Struct* curaa = zone->FindAA(x);
if(cur){
SetAA(x, 0);
for(int j = 0; j < cur; j++) {
m_pp.aapoints += curaa->cost + (curaa->cost_inc * j);
refunded = true;
}
}
else
{
m_pp.aapoints += cur;
SetAA(x, 0);
refunded = true;
}
}
}
if(refunded) {
SaveAA();
Save();
// Kick();
}
}
void Client::IncrementAA(int aa_id) {
SendAA_Struct* aa2 = zone->FindAA(aa_id);
if(aa2 == nullptr)
return;
if(GetAA(aa_id) == aa2->max_level)
return;
SetAA(aa_id, GetAA(aa_id) + 1);
SaveAA();
SendAA(aa_id);
SendAATable();
SendAAStats();
CalcBonuses();
}
void Client::SendItemScale(ItemInst *inst) { void Client::SendItemScale(ItemInst *inst) {
int slot = m_inv.GetSlotByItemInst(inst); int slot = m_inv.GetSlotByItemInst(inst);
if(slot != -1) { if(slot != -1) {

View File

@ -45,7 +45,6 @@ struct Item_Struct;
#include "../common/item_struct.h" #include "../common/item_struct.h"
#include "../common/clientversions.h" #include "../common/clientversions.h"
#include "aa.h"
#include "common.h" #include "common.h"
#include "merc.h" #include "merc.h"
#include "mob.h" #include "mob.h"
@ -227,6 +226,7 @@ public:
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
virtual void SetAttackTimer(); virtual void SetAttackTimer();
float GetQuiverHaste(); float GetQuiverHaste();
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
void AI_Init(); void AI_Init();
void AI_Start(uint32 iMoveDelay = 0); void AI_Start(uint32 iMoveDelay = 0);
@ -541,7 +541,6 @@ public:
bool Flurry(); bool Flurry();
bool Rampage(); bool Rampage();
void DurationRampage(uint32 duration);
inline uint32 GetEXP() const { return m_pp.exp; } inline uint32 GetEXP() const { return m_pp.exp; }
@ -623,6 +622,7 @@ public:
inline uint32 AccountID() const { return account_id; } inline uint32 AccountID() const { return account_id; }
inline const char* AccountName()const { return account_name; } inline const char* AccountName()const { return account_name; }
inline int GetAccountCreation() const { return account_creation; }
inline int16 Admin() const { return admin; } inline int16 Admin() const { return admin; }
inline uint32 CharacterID() const { return character_id; } inline uint32 CharacterID() const { return character_id; }
void UpdateAdmin(bool iFromDB = true); void UpdateAdmin(bool iFromDB = true);
@ -759,45 +759,35 @@ public:
inline PTimerList &GetPTimers() { return(p_timers); } inline PTimerList &GetPTimers() { return(p_timers); }
//AA Methods //New AA Methods
void SendAAList(); void SendAlternateAdvancementRank(int aa_id, int level);
void ResetAA(); void SendAlternateAdvancementTable();
void SendClearAA(); void SendAlternateAdvancementStats();
void SendAA(uint32 id, int seq=1); void PurchaseAlternateAdvancementRank(int rank_id);
void SendPreviousAA(uint32 id, int seq=1); bool GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost = false);
void BuyAA(AA_Action* action); void IncrementAlternateAdvancementRank(int rank_id);
//this function is used by some AA stuff void ActivateAlternateAdvancementAbility(int rank_id, int target_id);
void MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing); void SendAlternateAdvancementPoints();
void SetAATitle(const char *Title); void SendAlternateAdvancementTimer(int ability, int begin, int end);
void SetTitleSuffix(const char *txt); void SendAlternateAdvancementTimers();
inline uint32 GetMaxAAXP(void) const { return max_AAXP; } void ResetAlternateAdvancementTimer(int ability);
inline uint32 GetAAXP() const { return m_pp.expAA; } void ResetAlternateAdvancementTimers();
void SendAAStats();
void SendAATable(); void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAlternateAdvancementStats(); }
void SendAATimers(); void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAlternateAdvancementStats(); }
int GetAATimerID(aaID activate);
int CalcAAReuseTimer(const AA_DBAction *caa);
void ActivateAA(aaID activate);
void SendAATimer(uint32 ability, uint32 begin, uint32 end);
void EnableAAEffect(aaEffectType type, uint32 duration = 0);
void DisableAAEffect(aaEffectType type);
bool CheckAAEffect(aaEffectType type);
void HandleAAAction(aaID activate);
uint32 GetAA(uint32 aa_id) const;
bool SetAA(uint32 aa_id, uint32 new_value);
inline uint32 GetAAPointsSpent() { return m_pp.aapoints_spent; }
int16 CalcAAFocusEffect(focusType type, uint16 focus_spell, uint16 spell_id);
int16 CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id);
void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAAStats(); }
void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAAStats(); }
int GetAAPoints() { return m_pp.aapoints; } int GetAAPoints() { return m_pp.aapoints; }
int GetSpentAA() { return m_pp.aapoints_spent; } int GetSpentAA() { return m_pp.aapoints_spent; }
//old AA methods that we still use
void ResetAA();
void RefundAA(); void RefundAA();
void IncrementAA(int aa_id); void SendClearAA();
int32 GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2); inline uint32 GetMaxAAXP(void) const { return max_AAXP; }
int32 GetAAEffectid(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, true, false,false); } inline uint32 GetAAXP() const { return m_pp.expAA; }
int32 GetAABase1(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, true,false); } int16 CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id);
int32 GetAABase2(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, false,true); } void SetAATitle(const char *Title);
void SetTitleSuffix(const char *txt);
void MemorizeSpell(uint32 slot, uint32 spellid, uint32 scribing);
int32 acmod(); int32 acmod();
// Item methods // Item methods
@ -1271,8 +1261,6 @@ protected:
void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false); void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false);
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat); int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
void CalcEdibleBonuses(StatBonuses* newbon); void CalcEdibleBonuses(StatBonuses* newbon);
void CalcAABonuses(StatBonuses* newbon);
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
void ProcessItemCaps(); void ProcessItemCaps();
void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true); void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true);
bool client_data_loaded; bool client_data_loaded;
@ -1280,6 +1268,8 @@ protected:
int16 GetFocusEffect(focusType type, uint16 spell_id); int16 GetFocusEffect(focusType type, uint16 spell_id);
uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id); uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id);
void FinishAlternateAdvancementPurchase(AA::Rank *rank, bool ignore_cost);
Mob* bind_sight_target; Mob* bind_sight_target;
glm::vec4 m_AutoAttackPosition; glm::vec4 m_AutoAttackPosition;
@ -1497,11 +1487,7 @@ private:
uint32 tribute_master_id; uint32 tribute_master_id;
FILE *SQL_log;
uint32 max_AAXP; uint32 max_AAXP;
uint32 staminacount;
AA_Array* aa[MAX_PP_AA_ARRAY]; //this list contains pointers into our player profile
std::map<uint32,uint8> aa_points;
bool npcflag; bool npcflag;
uint8 npclevel; uint8 npclevel;
bool feigned; bool feigned;

View File

@ -1121,7 +1121,7 @@ int32 Client::CalcMaxMana()
switch (GetCasterClass()) { switch (GetCasterClass()) {
case 'I': case 'I':
case 'W': { case 'W': {
max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement()); max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
break; break;
} }
case 'N': { case 'N': {
@ -1978,7 +1978,18 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id) const
return 10; return 10;
uint32 effectmod = 10; uint32 effectmod = 10;
int effectmodcap = RuleI(Character, BaseInstrumentSoftCap); int effectmodcap = 0;
bool nocap = false;
if (RuleB(Character, UseSpellFileSongCap)) {
effectmodcap = spells[spell_id].songcap / 10;
// this looks a bit weird, but easiest way I could think to keep both systems working
if (effectmodcap == 0)
nocap = true;
else
effectmodcap += 10;
} else {
effectmodcap = RuleI(Character, BaseInstrumentSoftCap);
}
// this should never use spell modifiers... // this should never use spell modifiers...
// if a spell grants better modifers, they are copied into the item mods // if a spell grants better modifers, they are copied into the item mods
// because the spells are supposed to act just like having the intrument. // because the spells are supposed to act just like having the intrument.
@ -2048,10 +2059,11 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id) const
effectmod = 10; effectmod = 10;
return effectmod; return effectmod;
} }
if (!RuleB(Character, UseSpellFileSongCap))
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap; effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap;
if (effectmod < 10) if (effectmod < 10)
effectmod = 10; effectmod = 10;
if (effectmod > effectmodcap) if (!nocap && effectmod > effectmodcap) // if the cap is calculated to be 0 using new rules, no cap.
effectmod = effectmodcap; effectmod = effectmodcap;
Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", GetName(), spell_id, Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", GetName(), spell_id,
effectmod, effectmodcap); effectmod, effectmodcap);

View File

@ -389,6 +389,7 @@ void MapOpcodes()
ConnectedOpcodes[OP_XTargetRequest] = &Client::Handle_OP_XTargetRequest; ConnectedOpcodes[OP_XTargetRequest] = &Client::Handle_OP_XTargetRequest;
ConnectedOpcodes[OP_YellForHelp] = &Client::Handle_OP_YellForHelp; ConnectedOpcodes[OP_YellForHelp] = &Client::Handle_OP_YellForHelp;
ConnectedOpcodes[OP_ZoneChange] = &Client::Handle_OP_ZoneChange; ConnectedOpcodes[OP_ZoneChange] = &Client::Handle_OP_ZoneChange;
ConnectedOpcodes[OP_ResetAA] = &Client::Handle_OP_ResetAA;
} }
void ClearMappedOpcode(EmuOpcode op) void ClearMappedOpcode(EmuOpcode op)
@ -1082,7 +1083,7 @@ void Client::Handle_Connect_OP_ReqNewZone(const EQApplicationPacket *app)
void Client::Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app) void Client::Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app)
{ {
SendAATimers(); SendAlternateAdvancementTimers();
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAAStats, 0); EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAAStats, 0);
QueuePacket(outapp); QueuePacket(outapp);
safe_delete(outapp); safe_delete(outapp);
@ -1091,7 +1092,7 @@ void Client::Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app)
void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app) void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app)
{ {
SendAAList(); SendAlternateAdvancementTable();
return; return;
} }
@ -1152,7 +1153,7 @@ void Client::Handle_Connect_OP_TGB(const EQApplicationPacket *app)
void Client::Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app) void Client::Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app)
{ {
SendAATable(); SendAlternateAdvancementPoints();
} }
void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app) void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app)
@ -1439,58 +1440,15 @@ 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_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 (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; }
/* Initialize AA's : Move to function eventually */ if(RuleB(World, UseClientBasedExpansionSettings)) {
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++) m_pp.expansions = ExpansionFromClientVersion(GetClientVersion());
aa[a] = &m_pp.aa_array[a];
query = StringFormat(
"SELECT "
"slot, "
"aa_id, "
"aa_value, "
"charges "
"FROM "
"`character_alternate_abilities` "
"WHERE `id` = %u ORDER BY `slot`", this->CharacterID());
results = database.QueryDatabase(query); i = 0;
int offset = 0; // offset to fix the hole from expendables
for (auto row = results.begin(); row != results.end(); ++row) {
i = atoi(row[0]) - offset;
m_pp.aa_array[i].AA = atoi(row[1]);
m_pp.aa_array[i].value = atoi(row[2]);
m_pp.aa_array[i].charges = atoi(row[3]);
/* A used expendable could cause there to be a "hole" in the array, this is very bad. Bad things like keeping your expendable after use.
We could do a few things, one of them being reshuffling when the hole is created or defer the fixing until a later point, like during load!
Or just never making a hole in the array and just have hacks every where. Fixing the hole at load really just keeps 1 hack in Client::SendAATable
and keeping this offset that will cause the next AA to be pushed back over the hole. We also need to clean up on save so we don't have multiple
entries for a single AA.
*/
if (m_pp.aa_array[i].value == 0)
offset++;
} }
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ else {
uint32 id = aa[a]->AA; m_pp.expansions = RuleI(World, ExpansionSettings);
//watch for invalid AA IDs
if (id == aaNone)
continue;
if (id >= aaHighestID) {
aa[a]->AA = aaNone;
aa[a]->value = 0;
continue;
}
if (aa[a]->value == 0) {
aa[a]->AA = aaNone;
continue;
}
if (aa[a]->value > HIGHEST_AA_VALUE) {
aa[a]->AA = aaNone;
aa[a]->value = 0;
continue;
} }
if (aa[a]->value > 1) /* hack in some stuff for sony's new AA method (where each level of each aa.has a seperate ID) */ if(!database.LoadAlternateAdvancement(this)) {
aa_points[(id - aa[a]->value + 1)] = aa[a]->value; Log.Out(Logs::General, Logs::Error, "Error loading AA points for %s", GetName());
else
aa_points[id] = aa[a]->value;
} }
if (SPDAT_RECORDS > 0) { if (SPDAT_RECORDS > 0) {
@ -1615,11 +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. */ /* Update LFP in case any (or all) of our group disbanded while we were zoning. */
if (IsLFP()) { UpdateLFP(); } if (IsLFP()) { UpdateLFP(); }
/* Get Expansions from variables table and ship via PP */
char val[20] = { 0 };
if (database.GetVariable("Expansions", val, 20)){ m_pp.expansions = atoi(val); }
else{ m_pp.expansions = 0x3FF; }
p_timers.SetCharID(CharacterID()); p_timers.SetCharID(CharacterID());
if (!p_timers.Load(&database)) { if (!p_timers.Load(&database)) {
Log.Out(Logs::General, Logs::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID()); Log.Out(Logs::General, Logs::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID());
@ -1794,38 +1747,39 @@ void Client::Handle_OP_AAAction(const EQApplicationPacket *app)
Log.Out(Logs::Detail, Logs::AA, "Received OP_AAAction"); Log.Out(Logs::Detail, Logs::AA, "Received OP_AAAction");
if (app->size != sizeof(AA_Action)){ if (app->size != sizeof(AA_Action)){
printf("Error! OP_AAAction size didnt match!\n"); Log.Out(Logs::General, Logs::AA, "Error! OP_AAAction size didnt match!");
return; return;
} }
AA_Action* action = (AA_Action*)app->pBuffer; AA_Action* action = (AA_Action*)app->pBuffer;
if (action->action == aaActionActivate) {//AA Hotkey if (action->action == aaActionActivate) {//AA Hotkey
Log.Out(Logs::Detail, Logs::AA, "Activating AA %d", action->ability); Log.Out(Logs::Detail, Logs::AA, "Activating AA %d", action->ability);
ActivateAA((aaID)action->ability); ActivateAlternateAdvancementAbility(action->ability, action->target_id);
} }
else if (action->action == aaActionBuy) { else if (action->action == aaActionBuy) {
BuyAA(action); PurchaseAlternateAdvancementRank(action->ability);
} }
else if (action->action == aaActionDisableEXP){ //Turn Off AA Exp else if (action->action == aaActionDisableEXP){ //Turn Off AA Exp
if (m_epp.perAA > 0) if (m_epp.perAA > 0)
Message_StringID(0, AA_OFF); Message_StringID(0, AA_OFF);
m_epp.perAA = 0; m_epp.perAA = 0;
SendAAStats(); SendAlternateAdvancementStats();
} }
else if (action->action == aaActionSetEXP) { else if (action->action == aaActionSetEXP) {
if (m_epp.perAA == 0) if (m_epp.perAA == 0)
Message_StringID(0, AA_ON); Message_StringID(0, AA_ON);
m_epp.perAA = action->exp_value; m_epp.perAA = action->exp_value;
if (m_epp.perAA<0 || m_epp.perAA>100) m_epp.perAA = 0; // stop exploit with sanity check if (m_epp.perAA < 0 || m_epp.perAA > 100)
m_epp.perAA = 0; // stop exploit with sanity check
// send an update // send an update
SendAAStats(); SendAlternateAdvancementStats();
SendAATable(); SendAlternateAdvancementTable();
} }
else { else {
printf("Unknown AA action: %u %u 0x%x %d\n", action->action, action->ability, action->unknown08, action->exp_value); Log.Out(Logs::General, Logs::AA, "Unknown AA action : %u %u %u %d", action->action, action->ability, action->target_id, action->exp_value);
} }
return;
} }
void Client::Handle_OP_AcceptNewTask(const EQApplicationPacket *app) void Client::Handle_OP_AcceptNewTask(const EQApplicationPacket *app)
@ -3898,8 +3852,6 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
return; return;
} }
m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos);
CastSpell(spell_to_cast, castspell->target_id, castspell->slot); CastSpell(spell_to_cast, castspell->target_id, castspell->slot);
} }
/* Spell Slot or Potion Belt Slot */ /* Spell Slot or Potion Belt Slot */
@ -8852,7 +8804,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app)
pack->WriteUInt32(QSG_LFGuild_UpdatePlayerInfo); pack->WriteUInt32(QSG_LFGuild_UpdatePlayerInfo);
pack->WriteUInt32(GetBaseClass()); pack->WriteUInt32(GetBaseClass());
pack->WriteUInt32(GetLevel()); pack->WriteUInt32(GetLevel());
pack->WriteUInt32(GetAAPointsSpent()); pack->WriteUInt32(GetSpentAA());
pack->WriteString(pts->Comment); pack->WriteString(pts->Comment);
pack->WriteUInt32(pts->Toggle); pack->WriteUInt32(pts->Toggle);
pack->WriteUInt32(pts->TimeZone); pack->WriteUInt32(pts->TimeZone);
@ -14228,9 +14180,12 @@ void Client::Handle_OP_YellForHelp(const EQApplicationPacket *app)
return; return;
} }
/* void Client::Handle_OP_ResetAA(const EQApplicationPacket *app)
void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app)
{ {
if(Admin() >= 50) {
Message(0, "Resetting AA points.");
ResetAA();
}
return; return;
} }
*/

View File

@ -295,3 +295,4 @@
void Handle_OP_XTargetRequest(const EQApplicationPacket *app); void Handle_OP_XTargetRequest(const EQApplicationPacket *app);
void Handle_OP_YellForHelp(const EQApplicationPacket *app); void Handle_OP_YellForHelp(const EQApplicationPacket *app);
void Handle_OP_ZoneChange(const EQApplicationPacket *app); void Handle_OP_ZoneChange(const EQApplicationPacket *app);
void Handle_OP_ResetAA(const EQApplicationPacket *app);

View File

@ -391,73 +391,12 @@ bool Client::Process() {
} }
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
{ {
if(CheckAAEffect(aaEffectRampage))
{
entity_list.AEAttack(this, 30);
} else {
Attack(auto_attack_target, MainPrimary); // Kaiyodo - added attacking hand to arguments
}
ItemInst *wpn = GetInv().GetItem(MainPrimary); ItemInst *wpn = GetInv().GetItem(MainPrimary);
TryWeaponProc(wpn, auto_attack_target, MainPrimary); TryWeaponProc(wpn, auto_attack_target, MainPrimary);
bool tripleAttackSuccess = false; DoAttackRounds(auto_attack_target, MainPrimary);
if( auto_attack_target && CanThisClassDoubleAttack() ) { if (CheckAATimer(aaTimerRampage))
CheckIncreaseSkill(SkillDoubleAttack, auto_attack_target, -10);
if(CheckDoubleAttack()) {
//should we allow rampage on double attack?
if(CheckAAEffect(aaEffectRampage)) {
entity_list.AEAttack(this, 30); entity_list.AEAttack(this, 30);
} else {
Attack(auto_attack_target, MainPrimary, false);
}
}
//triple attack: rangers, monks, warriors, berserkers over level 60
if((((GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER)
&& GetLevel() >= 60) || GetSpecialAbility(SPECATK_TRIPLE))
&& CheckDoubleAttack(true))
{
tripleAttackSuccess = true;
Attack(auto_attack_target, MainPrimary, false);
}
//quad attack, does this belong here??
if(GetSpecialAbility(SPECATK_QUAD) && CheckDoubleAttack(true))
{
Attack(auto_attack_target, MainPrimary, false);
}
}
//Live AA - Flurry, Rapid Strikes ect (Flurry does not require Triple Attack).
int16 flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance;
if (auto_attack_target && flurrychance)
{
if(zone->random.Int(0, 99) < flurrychance)
{
Message_StringID(MT_NPCFlurry, YOU_FLURRY);
Attack(auto_attack_target, MainPrimary, false);
Attack(auto_attack_target, MainPrimary, false);
}
}
int16 ExtraAttackChanceBonus = spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance;
if (auto_attack_target && ExtraAttackChanceBonus) {
ItemInst *wpn = GetInv().GetItem(MainPrimary);
if(wpn){
if(wpn->GetItem()->ItemType == ItemType2HSlash ||
wpn->GetItem()->ItemType == ItemType2HBlunt ||
wpn->GetItem()->ItemType == ItemType2HPiercing )
{
if(zone->random.Int(0, 99) < ExtraAttackChanceBonus)
{
Attack(auto_attack_target, MainPrimary, false);
}
}
}
}
} }
} }
@ -498,23 +437,11 @@ bool Client::Process() {
float random = zone->random.Real(0, 1); float random = zone->random.Real(0, 1);
CheckIncreaseSkill(SkillDualWield, auto_attack_target, -10); CheckIncreaseSkill(SkillDualWield, auto_attack_target, -10);
if (random < DualWieldProbability){ // Max 78% of DW if (random < DualWieldProbability) { // Max 78% of DW
if(CheckAAEffect(aaEffectRampage)) {
entity_list.AEAttack(this, 30, MainSecondary);
} else {
Attack(auto_attack_target, MainSecondary); // Single attack with offhand
}
ItemInst *wpn = GetInv().GetItem(MainSecondary); ItemInst *wpn = GetInv().GetItem(MainSecondary);
TryWeaponProc(wpn, auto_attack_target, MainSecondary); TryWeaponProc(wpn, auto_attack_target, MainSecondary);
if( CanThisClassDoubleAttack() && CheckDoubleAttack()) { DoAttackRounds(auto_attack_target, MainSecondary);
if(CheckAAEffect(aaEffectRampage)) {
entity_list.AEAttack(this, 30, MainSecondary);
} else {
if(auto_attack_target && auto_attack_target->GetHP() > -10)
Attack(auto_attack_target, MainSecondary); // Single attack with offhand
}
}
} }
} }
} }

View File

@ -167,7 +167,6 @@ int command_init(void) {
command_add("aggro", "(range) [-v] - Display aggro information for all mobs 'range' distance from your target. -v is verbose faction info.", 80, command_aggro) || command_add("aggro", "(range) [-v] - Display aggro information for all mobs 'range' distance from your target. -v is verbose faction info.", 80, command_aggro) ||
command_add("aggrozone", "[aggro] - Aggro every mob in the zone with X aggro. Default is 0. Not recommend if you're not invulnerable.", 100, command_aggrozone) || command_add("aggrozone", "[aggro] - Aggro every mob in the zone with X aggro. Default is 0. Not recommend if you're not invulnerable.", 100, command_aggrozone) ||
command_add("ai", "[factionid/spellslist/con/guard/roambox/stop/start] - Modify AI on NPC target", 100, command_ai) || command_add("ai", "[factionid/spellslist/con/guard/roambox/stop/start] - Modify AI on NPC target", 100, command_ai) ||
command_add("altactivate", "[argument] - activates alternate advancement abilities, use altactivate help for more information", 0, command_altactivate) ||
command_add("appearance", "[type] [value] - Send an appearance packet for you or your target", 150, command_appearance) || command_add("appearance", "[type] [value] - Send an appearance packet for you or your target", 150, command_appearance) ||
command_add("attack", "[targetname] - Make your NPC target attack targetname", 150, command_attack) || command_add("attack", "[targetname] - Make your NPC target attack targetname", 150, command_attack) ||
command_add("augmentitem", "Force augments an item. Must have the augment item window open.", 250, command_augmentitem) || command_add("augmentitem", "Force augments an item. Must have the augment item window open.", 250, command_augmentitem) ||
@ -273,7 +272,6 @@ int command_init(void) {
command_add("los", nullptr,0, command_checklos) || command_add("los", nullptr,0, command_checklos) ||
command_add("makepet", "[level] [class] [race] [texture] - Make a pet", 50, command_makepet) || command_add("makepet", "[level] [class] [race] [texture] - Make a pet", 50, command_makepet) ||
command_add("mana", "- Fill your or your target's mana", 50, command_mana) || command_add("mana", "- Fill your or your target's mana", 50, command_mana) ||
command_add("manaburn", "- Use AA Wizard class skill manaburn on target", 10, command_manaburn) ||
command_add("maxskills", "Maxes skills for you.", 200, command_max_all_skills) || command_add("maxskills", "Maxes skills for you.", 200, command_max_all_skills) ||
command_add("memspell", "[slotid] [spellid] - Memorize spellid in the specified slot", 50, command_memspell) || command_add("memspell", "[slotid] [spellid] - Memorize spellid in the specified slot", 50, command_memspell) ||
command_add("merchant_close_shop", "Closes a merchant shop", 100, command_merchantcloseshop) || command_add("merchant_close_shop", "Closes a merchant shop", 100, command_merchantcloseshop) ||
@ -322,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("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("randomfeatures", "- Temporarily randomizes the Facial Features of your target", 80, command_randomfeatures) ||
command_add("refreshgroup", "- Refreshes Group.", 0, command_refreshgroup) || 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("reloadallrules", "Executes a reload of all rules.", 80, command_reloadallrules) ||
command_add("reloademote", "Reloads NPC Emotes", 80, command_reloademote) || command_add("reloademote", "Reloads NPC Emotes", 80, command_reloademote) ||
command_add("reloadlevelmods", nullptr,255, command_reloadlevelmods) || command_add("reloadlevelmods", nullptr,255, command_reloadlevelmods) ||
@ -334,7 +333,8 @@ int command_init(void) {
command_add("reloadzonepoints", "- Reload zone points from database", 150, command_reloadzps) || command_add("reloadzonepoints", "- Reload zone points from database", 150, command_reloadzps) ||
command_add("reloadzps", nullptr,0, command_reloadzps) || command_add("reloadzps", nullptr,0, command_reloadzps) ||
command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) || 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, disconnects player.", 200, command_resetaa) || 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("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("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) || command_add("save", "- Force your player or player corpse target to be saved to the database", 50, command_save) ||
@ -673,8 +673,8 @@ void command_incstat(Client* c, const Seperator* sep){
} }
} }
void command_resetaa(Client* c,const Seperator *sep){ void command_resetaa(Client* c,const Seperator *sep) {
if(c->GetTarget()!=0 && c->GetTarget()->IsClient()){ if(c->GetTarget() && c->GetTarget()->IsClient()){
c->GetTarget()->CastToClient()->ResetAA(); c->GetTarget()->CastToClient()->ResetAA();
c->Message(13,"Successfully reset %s's AAs", c->GetTarget()->GetName()); c->Message(13,"Successfully reset %s's AAs", c->GetTarget()->GetName());
} }
@ -4840,36 +4840,6 @@ void command_zonestatus(Client *c, const Seperator *sep)
} }
} }
void command_manaburn(Client *c, const Seperator *sep)
{
Mob* target=c->GetTarget();
if (c->GetTarget() == 0)
c->Message(0, "#Manaburn needs a target.");
else {
int cur_level=c->GetAA(MANA_BURN);//ManaBurn ID
if (DistanceSquared(c->GetPosition(), target->GetPosition()) > 200)
c->Message(0,"You are too far away from your target.");
else {
if(cur_level == 1) {
if(c->IsAttackAllowed(target))
{
c->SetMana(0);
int nukedmg=(c->GetMana())*2;
if (nukedmg>0)
{
target->Damage(c, nukedmg, 2751, SkillAbjuration/*hackish*/);
c->Message(4,"You unleash an enormous blast of magical energies.");
}
Log.Out(Logs::General, Logs::Normal, "Manaburn request from %s, damage: %d", c->GetName(), nukedmg);
}
}
else
c->Message(0, "You have not learned this skill.");
}
}
}
void command_doanim(Client *c, const Seperator *sep) void command_doanim(Client *c, const Seperator *sep)
{ {
if (!sep->IsNumber(1)) if (!sep->IsNumber(1))
@ -5584,16 +5554,23 @@ void command_setaapts(Client *c, const Seperator *sep)
if(sep->arg[1][0] == '\0' || sep->arg[2][0] == '\0') if(sep->arg[1][0] == '\0' || sep->arg[2][0] == '\0')
c->Message(0, "Usage: #setaapts <AA|group|raid> <new AA points value>"); c->Message(0, "Usage: #setaapts <AA|group|raid> <new AA points value>");
else if(atoi(sep->arg[2]) <= 0 || atoi(sep->arg[2]) > 200) else if(atoi(sep->arg[2]) <= 0 || atoi(sep->arg[2]) > 5000)
c->Message(0, "You must have a number greater than 0 for points and no more than 200."); c->Message(0, "You must have a number greater than 0 for points and no more than 5000.");
else if(!strcasecmp(sep->arg[1], "group")) { else if(!strcasecmp(sep->arg[1], "group")) {
t->SetLeadershipEXP(atoi(sep->arg[2])*GROUP_EXP_PER_POINT, t->GetRaidEXP()); t->GetPP().group_leadership_points = atoi(sep->arg[2]);
t->GetPP().group_leadership_exp = 0;
t->Message(MT_Experience, "Setting Group AA points to %u", t->GetPP().group_leadership_points);
t->SendLeadershipEXPUpdate();
} else if(!strcasecmp(sep->arg[1], "raid")) { } else if(!strcasecmp(sep->arg[1], "raid")) {
t->SetLeadershipEXP(t->GetGroupEXP(), atoi(sep->arg[2])*RAID_EXP_PER_POINT); t->GetPP().raid_leadership_points = atoi(sep->arg[2]);
t->GetPP().raid_leadership_exp = 0;
t->Message(MT_Experience, "Setting Raid AA points to %u", t->GetPP().raid_leadership_points);
t->SendLeadershipEXPUpdate();
} else { } else {
t->SetEXP(t->GetEXP(),t->GetMaxAAXP()*atoi(sep->arg[2]),false); t->GetPP().aapoints = atoi(sep->arg[2]);
t->SendAAStats(); t->GetPP().expAA = 0;
t->SendAATable(); t->Message(MT_Experience, "Setting personal AA points to %u", t->GetPP().aapoints);
t->SendAlternateAdvancementStats();
} }
} }
@ -7676,56 +7653,6 @@ void command_reloadtitles(Client *c, const Seperator *sep)
} }
void command_altactivate(Client *c, const Seperator *sep){
if(sep->arg[1][0] == '\0'){
c->Message(10, "Invalid argument, usage:");
c->Message(10, "#altactivate list - lists the AA ID numbers that are available to you");
c->Message(10, "#altactivate time [argument] - returns the time left until you can use the AA with the ID that matches the argument.");
c->Message(10, "#altactivate [argument] - activates the AA with the ID that matches the argument.");
return;
}
if(!strcasecmp(sep->arg[1], "help")){
c->Message(10, "Usage:");
c->Message(10, "#altactivate list - lists the AA ID numbers that are available to you");
c->Message(10, "#altactivate time [argument] - returns the time left until you can use the AA with the ID that matches the argument.");
c->Message(10, "#altactivate [argument] - activates the AA with the ID that matches the argument.");
return;
}
if(!strcasecmp(sep->arg[1], "list")){
c->Message(10, "You have access to the following AA Abilities:");
int x, val;
SendAA_Struct* saa = nullptr;
for(x = 0; x < aaHighestID; x++){
if(AA_Actions[x][0].spell_id || AA_Actions[x][0].action){ //if there's an action or spell associated we assume it's a valid
val = 0; //and assume if they don't have a value for the first rank then it isn't valid for any rank
saa = nullptr;
val = c->GetAA(x);
if(val){
saa = zone->FindAA(x);
c->Message(10, "%d: %s %d", x, saa->name, val);
}
}
}
}
else if(!strcasecmp(sep->arg[1], "time")){
int ability = atoi(sep->arg[2]);
if(c->GetAA(ability)){
int remain = c->GetPTimers().GetRemainingTime(pTimerAAStart + ability);
if(remain)
c->Message(10, "You may use that ability in %d minutes and %d seconds.", (remain/60), (remain%60));
else
c->Message(10, "You may use that ability now.");
}
else{
c->Message(10, "You do not have access to that ability.");
}
}
else
{
c->ActivateAA((aaID) atoi(sep->arg[1]));
}
}
void command_traindisc(Client *c, const Seperator *sep) void command_traindisc(Client *c, const Seperator *sep)
{ {
uint8 max_level, min_level; uint8 max_level, min_level;
@ -10655,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); 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();
}

View File

@ -216,7 +216,6 @@ void command_time(Client *c, const Seperator *sep);
void command_guild(Client *c, const Seperator *sep); void command_guild(Client *c, const Seperator *sep);
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value); bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value);
void command_zonestatus(Client *c, const Seperator *sep); void command_zonestatus(Client *c, const Seperator *sep);
void command_manaburn(Client *c, const Seperator *sep);
void command_doanim(Client *c, const Seperator *sep); void command_doanim(Client *c, const Seperator *sep);
void command_randomfeatures(Client *c, const Seperator *sep); void command_randomfeatures(Client *c, const Seperator *sep);
void command_face(Client *c, const Seperator *sep); void command_face(Client *c, const Seperator *sep);
@ -276,7 +275,6 @@ void command_guildlist(Client *c, const Seperator *sep);
void command_rules(Client *c, const Seperator *sep); void command_rules(Client *c, const Seperator *sep);
void command_task(Client *c, const Seperator *sep); void command_task(Client *c, const Seperator *sep);
void command_reloadtitles(Client *c, const Seperator *sep); void command_reloadtitles(Client *c, const Seperator *sep);
void command_altactivate(Client *c, const Seperator *sep);
void command_refundaa(Client *c, const Seperator *sep); void command_refundaa(Client *c, const Seperator *sep);
void command_traindisc(Client *c, const Seperator *sep); void command_traindisc(Client *c, const Seperator *sep);
void command_deletegraveyard(Client *c, const Seperator *sep); void command_deletegraveyard(Client *c, const Seperator *sep);
@ -325,6 +323,8 @@ void command_tune(Client *c, const Seperator *sep);
void command_logtest(Client *c, const Seperator *sep); void command_logtest(Client *c, const Seperator *sep);
void command_mysqltest(Client *c, const Seperator *sep); void command_mysqltest(Client *c, const Seperator *sep);
void command_logs(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 #ifdef EQPROFILE
void command_profiledump(Client *c, const Seperator *sep); void command_profiledump(Client *c, const Seperator *sep);

View File

@ -22,6 +22,7 @@
#define TARGET_RING_SPELL_SLOT 12 #define TARGET_RING_SPELL_SLOT 12
#define DISCIPLINE_SPELL_SLOT 10 #define DISCIPLINE_SPELL_SLOT 10
#define ABILITY_SPELL_SLOT 9 #define ABILITY_SPELL_SLOT 9
#define ALTERNATE_ABILITY_SPELL_SLOT 0xFF
//LOS Parameters: //LOS Parameters:
#define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from #define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from
@ -400,7 +401,6 @@ struct StatBonuses {
int32 Metabolism; // Food/drink consumption rates. int32 Metabolism; // Food/drink consumption rates.
bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others. bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others.
int32 FactionModPct; // Modifies amount of faction gained. int32 FactionModPct; // Modifies amount of faction gained.
int32 MeleeVulnerability; // Weakness/mitigation to melee damage
bool LimitToSkill[HIGHEST_SKILL+2]; // Determines if we need to search for a skill proc. bool LimitToSkill[HIGHEST_SKILL+2]; // Determines if we need to search for a skill proc.
uint32 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs. uint32 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs.
uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success. uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success.
@ -412,7 +412,7 @@ struct StatBonuses {
int8 BaseMovementSpeed; // Adjust base run speed, does not stack with other movement bonuses. int8 BaseMovementSpeed; // Adjust base run speed, does not stack with other movement bonuses.
uint8 IncreaseRunSpeedCap; // Increase max run speed above cap. uint8 IncreaseRunSpeedCap; // Increase max run speed above cap.
int32 DoubleSpecialAttack; // Chance to to perform a double special attack (ie flying kick 2x) int32 DoubleSpecialAttack; // Chance to to perform a double special attack (ie flying kick 2x)
int32 SpecialAttackKBProc[2]; // Chance to to do a knockback from special attacks. (0 = chance 1 = Skill) int32 SkillAttackProc[3]; // [0] chance to proc [2] spell on [1] skill usage
uint8 FrontalStunResist; // Chance to resist a frontal stun uint8 FrontalStunResist; // Chance to resist a frontal stun
int32 BindWound; // Increase amount of HP by percent. int32 BindWound; // Increase amount of HP by percent.
int32 MaxBindWound; // Increase max amount of HP you can bind wound. int32 MaxBindWound; // Increase max amount of HP you can bind wound.
@ -461,6 +461,7 @@ struct StatBonuses {
uint8 AssassinateLevel; // Max Level Assassinate will be effective at. uint8 AssassinateLevel; // Max Level Assassinate will be effective at.
int32 PetMeleeMitigation; // Add AC to owner's pet. int32 PetMeleeMitigation; // Add AC to owner's pet.
bool IllusionPersistence; // Causes illusions not to fade. bool IllusionPersistence; // Causes illusions not to fade.
uint16 extra_xtargets; // extra xtarget entries
}; };
typedef struct typedef struct

View File

@ -421,12 +421,6 @@ int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
int tic_inc = 0; int tic_inc = 0;
tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id); tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);
// unsure on the exact details, but bard songs that don't cost mana at some point get an extra tick, 60 for now
// a level 53 bard reported getting 2 tics
// bard DOTs do get this extra tick, but beneficial long bard songs don't? (invul, crescendo)
if ((IsShortDurationBuff(spell_id) || IsDetrimentalSpell(spell_id)) && IsBardSong(spell_id) &&
spells[spell_id].mana == 0 && GetClass() == BARD && GetLevel() > 60)
tic_inc++;
float focused = ((duration * increase) / 100.0f) + tic_inc; float focused = ((duration * increase) / 100.0f) + tic_inc;
int ifocused = static_cast<int>(focused); int ifocused = static_cast<int>(focused);
@ -878,7 +872,7 @@ void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool aff
caster->CastToClient()->CheckSongSkillIncrease(spell_id); caster->CastToClient()->CheckSongSkillIncrease(spell_id);
} }
//Dook- Rampage and stuff for clients. // Rampage and stuff for clients. Normal and Duration rampages
//NPCs handle it differently in Mob::Rampage //NPCs handle it differently in Mob::Rampage
void EntityList::AEAttack(Mob *attacker, float dist, int Hand, int count, bool IsFromSpell) { void EntityList::AEAttack(Mob *attacker, float dist, int Hand, int count, bool IsFromSpell) {
//Dook- Will need tweaking, currently no pets or players or horses //Dook- Will need tweaking, currently no pets or players or horses
@ -896,7 +890,10 @@ void EntityList::AEAttack(Mob *attacker, float dist, int Hand, int count, bool I
&& curmob->GetRace() != 216 && curmob->GetRace() != 472 /* dont attack horses */ && curmob->GetRace() != 216 && curmob->GetRace() != 472 /* dont attack horses */
&& (DistanceSquared(curmob->GetPosition(), attacker->GetPosition()) <= dist2) && (DistanceSquared(curmob->GetPosition(), attacker->GetPosition()) <= dist2)
) { ) {
if (!attacker->IsClient() || attacker->GetClass() == MONK || attacker->GetClass() == RANGER)
attacker->Attack(curmob, Hand, false, false, IsFromSpell); attacker->Attack(curmob, Hand, false, false, IsFromSpell);
else
attacker->CastToClient()->DoAttackRounds(curmob, Hand, IsFromSpell);
hit++; hit++;
if (count != 0 && hit >= count) if (count != 0 && hit >= count)
return; return;

View File

@ -58,7 +58,6 @@ extern uint32 numclients;
extern PetitionList petition_list; extern PetitionList petition_list;
extern char errorname[32]; extern char errorname[32];
extern uint16 adverrornum;
Entity::Entity() Entity::Entity()
{ {
@ -4705,3 +4704,11 @@ void EntityList::StopMobAI()
mob.second->AI_ShutDown(); mob.second->AI_ShutDown();
} }
} }
void EntityList::SendAlternateAdvancementStats() {
for(auto &c : client_list) {
c.second->SendAlternateAdvancementTable();
c.second->SendAlternateAdvancementStats();
c.second->SendAlternateAdvancementPoints();
}
}

View File

@ -398,7 +398,6 @@ public:
void SaveAllClientsTaskState(); void SaveAllClientsTaskState();
void ReloadAllClientsTaskState(int TaskID=0); void ReloadAllClientsTaskState(int TaskID=0);
uint16 CreateGroundObject(uint32 itemid, const glm::vec4& position, uint32 decay_time = 300000); 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 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); uint16 CreateDoor(const char *model, const glm::vec4& position, uint8 type = 0, uint16 size = 100);
@ -429,6 +428,7 @@ public:
uint16 GetFreeID(); uint16 GetFreeID();
void RefreshAutoXTargets(Client *c); void RefreshAutoXTargets(Client *c);
void RefreshClientXTargets(Client *c); void RefreshClientXTargets(Client *c);
void SendAlternateAdvancementStats();
protected: protected:
friend class Zone; friend class Zone;

View File

@ -515,7 +515,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
if (GetLevel() < 51) { if (GetLevel() < 51) {
m_epp.perAA = 0; // turn off aa exp if they drop below 51 m_epp.perAA = 0; // turn off aa exp if they drop below 51
} else } else
SendAAStats(); //otherwise, send them an AA update SendAlternateAdvancementStats(); //otherwise, send them an AA update
//send the expdata in any case so the xp bar isnt stuck after leveling //send the expdata in any case so the xp bar isnt stuck after leveling
uint32 tmpxp1 = GetEXPForLevel(GetLevel()+1); uint32 tmpxp1 = GetEXPForLevel(GetLevel()+1);

View File

@ -350,6 +350,11 @@ const char *Lua_Client::AccountName() {
return self->AccountName(); return self->AccountName();
} }
int Lua_Client::GetAccountAge() {
Lua_Safe_Call_Int();
return time(nullptr) - self->GetAccountCreation();
}
int Lua_Client::Admin() { int Lua_Client::Admin() {
Lua_Safe_Call_Bool(); Lua_Safe_Call_Bool();
return self->Admin(); return self->Admin();
@ -1024,7 +1029,17 @@ void Lua_Client::AddLevelBasedExp(int exp_pct, int max_level) {
void Lua_Client::IncrementAA(int aa) { void Lua_Client::IncrementAA(int aa) {
Lua_Safe_Call_Void(); Lua_Safe_Call_Void();
self->IncrementAA(aa); self->IncrementAlternateAdvancementRank(aa);
}
bool Lua_Client::GrantAlternateAdvancementAbility(int aa_id, int points) {
Lua_Safe_Call_Bool();
self->GrantAlternateAdvancementAbility(aa_id, points);
}
bool Lua_Client::GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost) {
Lua_Safe_Call_Bool();
self->GrantAlternateAdvancementAbility(aa_id, points, ignore_cost);
} }
void Lua_Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z) { void Lua_Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z) {
@ -1365,6 +1380,7 @@ luabind::scope lua_register_client() {
.def("GetRawItemAC", (int(Lua_Client::*)(void))&Lua_Client::GetRawItemAC) .def("GetRawItemAC", (int(Lua_Client::*)(void))&Lua_Client::GetRawItemAC)
.def("AccountID", (uint32(Lua_Client::*)(void))&Lua_Client::AccountID) .def("AccountID", (uint32(Lua_Client::*)(void))&Lua_Client::AccountID)
.def("AccountName", (const char *(Lua_Client::*)(void))&Lua_Client::AccountName) .def("AccountName", (const char *(Lua_Client::*)(void))&Lua_Client::AccountName)
.def("GetAccountAge", (int(Lua_Client::*)(void))&Lua_Client::GetAccountAge)
.def("Admin", (int(Lua_Client::*)(void))&Lua_Client::Admin) .def("Admin", (int(Lua_Client::*)(void))&Lua_Client::Admin)
.def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID) .def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID)
.def("GuildRank", (int(Lua_Client::*)(void))&Lua_Client::GuildRank) .def("GuildRank", (int(Lua_Client::*)(void))&Lua_Client::GuildRank)
@ -1500,6 +1516,8 @@ luabind::scope lua_register_client() {
.def("AddLevelBasedExp", (void(Lua_Client::*)(int))&Lua_Client::AddLevelBasedExp) .def("AddLevelBasedExp", (void(Lua_Client::*)(int))&Lua_Client::AddLevelBasedExp)
.def("AddLevelBasedExp", (void(Lua_Client::*)(int,int))&Lua_Client::AddLevelBasedExp) .def("AddLevelBasedExp", (void(Lua_Client::*)(int,int))&Lua_Client::AddLevelBasedExp)
.def("IncrementAA", (void(Lua_Client::*)(int))&Lua_Client::IncrementAA) .def("IncrementAA", (void(Lua_Client::*)(int))&Lua_Client::IncrementAA)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility)
.def("MarkSingleCompassLoc", (void(Lua_Client::*)(float,float,float))&Lua_Client::MarkSingleCompassLoc) .def("MarkSingleCompassLoc", (void(Lua_Client::*)(float,float,float))&Lua_Client::MarkSingleCompassLoc)
.def("MarkSingleCompassLoc", (void(Lua_Client::*)(float,float,float,int))&Lua_Client::MarkSingleCompassLoc) .def("MarkSingleCompassLoc", (void(Lua_Client::*)(float,float,float,int))&Lua_Client::MarkSingleCompassLoc)
.def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(void))&Lua_Client::GetNextAvailableSpellBookSlot) .def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(void))&Lua_Client::GetNextAvailableSpellBookSlot)

View File

@ -233,6 +233,8 @@ public:
void AddLevelBasedExp(int exp_pct); void AddLevelBasedExp(int exp_pct);
void AddLevelBasedExp(int exp_pct, int max_level); void AddLevelBasedExp(int exp_pct, int max_level);
void IncrementAA(int aa); void IncrementAA(int aa);
bool GrantAlternateAdvancementAbility(int aa_id, int points);
bool GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost);
void MarkSingleCompassLoc(float in_x, float in_y, float in_z); void MarkSingleCompassLoc(float in_x, float in_y, float in_z);
void MarkSingleCompassLoc(float in_x, float in_y, float in_z, int count); void MarkSingleCompassLoc(float in_x, float in_y, float in_z, int count);
int GetNextAvailableSpellBookSlot(); int GetNextAvailableSpellBookSlot();
@ -260,6 +262,7 @@ public:
bool HasSpellScribed(int spell_id); bool HasSpellScribed(int spell_id);
void SetAccountFlag(std::string flag, std::string val); void SetAccountFlag(std::string flag, std::string val);
std::string GetAccountFlag(std::string flag); std::string GetAccountFlag(std::string flag);
int GetAccountAge();
Lua_Group GetGroup(); Lua_Group GetGroup();
Lua_Raid GetRaid(); Lua_Raid GetRaid();
bool PutItemInInventory(int slot_id, Lua_ItemInst inst); bool PutItemInInventory(int slot_id, Lua_ItemInst inst);

View File

@ -790,7 +790,7 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, in
int16 res = resist_adjust; int16 res = resist_adjust;
return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot), return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast<uint32>(item_slot),
static_cast<uint32>(timer), static_cast<uint32>(timer_duration), 0, &res); static_cast<uint32>(timer), static_cast<uint32>(timer_duration), &res);
} }
bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target) { bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target) {
@ -1195,6 +1195,21 @@ int Lua_Mob::GetAA(int id) {
return self->GetAA(id); return self->GetAA(id);
} }
int Lua_Mob::GetAAByAAID(int id) {
Lua_Safe_Call_Int();
return self->GetAAByAAID(id);
}
bool Lua_Mob::SetAA(int rank_id, int new_value) {
Lua_Safe_Call_Bool();
return self->SetAA(rank_id, new_value);
}
bool Lua_Mob::SetAA(int rank_id, int new_value, int charges) {
Lua_Safe_Call_Bool();
return self->SetAA(rank_id, new_value, charges);
}
bool Lua_Mob::DivineAura() { bool Lua_Mob::DivineAura() {
Lua_Safe_Call_Bool(); Lua_Safe_Call_Bool();
return self->DivineAura(); return self->DivineAura();
@ -2074,6 +2089,9 @@ luabind::scope lua_register_mob() {
.def("CheckHealAggroAmount", (int(Lua_Mob::*)(int))&Lua_Mob::CheckHealAggroAmount) .def("CheckHealAggroAmount", (int(Lua_Mob::*)(int))&Lua_Mob::CheckHealAggroAmount)
.def("CheckHealAggroAmount", (int(Lua_Mob::*)(int,uint32))&Lua_Mob::CheckHealAggroAmount) .def("CheckHealAggroAmount", (int(Lua_Mob::*)(int,uint32))&Lua_Mob::CheckHealAggroAmount)
.def("GetAA", (int(Lua_Mob::*)(int))&Lua_Mob::GetAA) .def("GetAA", (int(Lua_Mob::*)(int))&Lua_Mob::GetAA)
.def("GetAAByAAID", (int(Lua_Mob::*)(int))&Lua_Mob::GetAAByAAID)
.def("SetAA", (bool(Lua_Mob::*)(int,int))&Lua_Mob::SetAA)
.def("SetAA", (bool(Lua_Mob::*)(int,int,int))&Lua_Mob::SetAA)
.def("DivineAura", (bool(Lua_Mob::*)(void))&Lua_Mob::DivineAura) .def("DivineAura", (bool(Lua_Mob::*)(void))&Lua_Mob::DivineAura)
.def("SetOOCRegen", (void(Lua_Mob::*)(int))&Lua_Mob::SetOOCRegen) .def("SetOOCRegen", (void(Lua_Mob::*)(int))&Lua_Mob::SetOOCRegen)
.def("GetEntityVariable", (const char*(Lua_Mob::*)(const char*))&Lua_Mob::GetEntityVariable) .def("GetEntityVariable", (const char*(Lua_Mob::*)(const char*))&Lua_Mob::GetEntityVariable)

View File

@ -249,6 +249,9 @@ public:
int CheckHealAggroAmount(int spell_id); int CheckHealAggroAmount(int spell_id);
int CheckHealAggroAmount(int spell_id, uint32 heal_possible); int CheckHealAggroAmount(int spell_id, uint32 heal_possible);
int GetAA(int id); int GetAA(int id);
int GetAAByAAID(int id);
bool SetAA(int rank_id, int new_value);
bool SetAA(int rank_id, int new_value, int charges);
bool DivineAura(); bool DivineAura();
void SetOOCRegen(int regen); void SetOOCRegen(int regen);
const char* GetEntityVariable(const char *name); const char* GetEntityVariable(const char *name);

View File

@ -307,8 +307,8 @@ Mob::Mob(const char* in_name,
casting_spell_id = 0; casting_spell_id = 0;
casting_spell_timer = 0; casting_spell_timer = 0;
casting_spell_timer_duration = 0; casting_spell_timer_duration = 0;
casting_spell_type = 0;
casting_spell_inventory_slot = 0; casting_spell_inventory_slot = 0;
casting_spell_aa_id = 0;
target = 0; target = 0;
ActiveProjectileATK = false; ActiveProjectileATK = false;
@ -1142,6 +1142,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
else else
ns->spawn.flymode = flymode; ns->spawn.flymode = flymode;
if(IsBoat()) {
ns->spawn.flymode = 1;
}
ns->spawn.lastName[0] = '\0'; ns->spawn.lastName[0] = '\0';
strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName)); strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName));
@ -3510,9 +3514,11 @@ void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger)
uint32 trigger_spell_id = 0; uint32 trigger_spell_id = 0;
if (aa_trigger && IsClient()){ if (aa_trigger && IsClient()) {
//focus_spell = aaid // focus_spell = aaid
trigger_spell_id = CastToClient()->CalcAAFocus(focusTriggerOnCast, focus_spell, spell_id); auto rank = zone->GetAlternateAdvancementRank(focus_spell);
if (rank)
trigger_spell_id = CastToClient()->CalcAAFocus(focusTriggerOnCast, *rank, spell_id);
if(IsValidSpell(trigger_spell_id) && GetTarget()) if(IsValidSpell(trigger_spell_id) && GetTarget())
SpellFinished(trigger_spell_id, GetTarget(), 10, 0, -1, spells[trigger_spell_id].ResistDiff); SpellFinished(trigger_spell_id, GetTarget(), 10, 0, -1, spells[trigger_spell_id].ResistDiff);
@ -3768,11 +3774,8 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] + skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] +
itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used]; itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used];
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1]; skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
skilldmg_mod += spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability;
if(skilldmg_mod < -100) if(skilldmg_mod < -100)
skilldmg_mod = -100; skilldmg_mod = -100;

View File

@ -23,6 +23,8 @@
#include "hate_list.h" #include "hate_list.h"
#include "pathing.h" #include "pathing.h"
#include "position.h" #include "position.h"
#include "aa_ability.h"
#include "aa.h"
#include <set> #include <set>
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -221,10 +223,12 @@ public:
virtual void SpellProcess(); virtual void SpellProcess();
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1,
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, uint32 type = 0, int16 *resist_adjust = nullptr); uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 *resist_adjust = nullptr,
uint32 aa_id = 0);
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1,
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, uint32 type = 0, int16 resist_adjust = 0); uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 resist_adjust = 0,
uint32 aa_id = 0);
void CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint16 mana_used, void CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint16 mana_used,
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0); uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0, bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0,
@ -860,7 +864,6 @@ public:
uint32 GetZoneID() const; //for perl uint32 GetZoneID() const; //for perl
virtual int32 CheckAggroAmount(uint16 spell_id, bool isproc = false); virtual int32 CheckAggroAmount(uint16 spell_id, bool isproc = false);
virtual int32 CheckHealAggroAmount(uint16 spell_id, uint32 heal_possible = 0); virtual int32 CheckHealAggroAmount(uint16 spell_id, uint32 heal_possible = 0);
virtual uint32 GetAA(uint32 aa_id) const { return(0); }
uint32 GetInstrumentMod(uint16 spell_id) const; uint32 GetInstrumentMod(uint16 spell_id) const;
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0); int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0);
@ -956,6 +959,19 @@ public:
void Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int avoid_override, int Msg = 0); void Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int avoid_override, int Msg = 0);
void Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int acc_override, int Msg = 0); void Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int acc_override, int Msg = 0);
//aa new
uint32 GetAA(uint32 rank_id, uint32 *charges = nullptr) const;
uint32 GetAAByAAID(uint32 aa_id, uint32 *charges = nullptr) const;
bool SetAA(uint32 rank_id, uint32 new_value, uint32 charges = 0);
void ClearAAs() { aa_ranks.clear(); }
bool CanUseAlternateAdvancementRank(AA::Rank *rank);
bool CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant);
int GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in);
void ExpendAlternateAdvancementCharge(uint32 aa_id);
void CalcAABonuses(StatBonuses* newbon);
void ApplyAABonuses(const AA::Rank &rank, StatBonuses* newbon);
bool CheckAATimer(int timer);
protected: protected:
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic); void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic);
static uint16 GetProcID(uint16 spell_id, uint8 effect_index); static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
@ -969,7 +985,6 @@ protected:
virtual bool AI_PursueCastCheck() { return(false); } virtual bool AI_PursueCastCheck() { return(false); }
virtual bool AI_IdleCastCheck() { return(false); } virtual bool AI_IdleCastCheck() { return(false); }
bool IsFullHP; bool IsFullHP;
bool moved; bool moved;
@ -1145,6 +1160,7 @@ protected:
uint32 casting_spell_timer_duration; uint32 casting_spell_timer_duration;
uint32 casting_spell_type; uint32 casting_spell_type;
int16 casting_spell_resist_adjust; int16 casting_spell_resist_adjust;
uint32 casting_spell_aa_id;
bool casting_spell_checks; bool casting_spell_checks;
uint16 bardsong; uint16 bardsong;
uint8 bardsong_slot; uint8 bardsong_slot;
@ -1311,6 +1327,9 @@ protected:
bool bEnraged; bool bEnraged;
bool destructibleobject; bool destructibleobject;
std::unordered_map<uint32, std::pair<uint32, uint32>> aa_ranks;
Timer aa_timers[aaTimerMax];
private: private:
void _StopSong(); //this is not what you think it is void _StopSong(); //this is not what you think it is
Mob* target; Mob* target;

View File

@ -342,7 +342,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
SetCurrentSpeed(0); SetCurrentSpeed(0);
} }
return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0, &(AIspells[i].resist_adjust)); return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, &(AIspells[i].resist_adjust));
} }
bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint16 iSpellTypes) { bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint16 iSpellTypes) {

View File

@ -96,7 +96,6 @@ EntityList entity_list;
WorldServer worldserver; WorldServer worldserver;
uint32 numclients = 0; uint32 numclients = 0;
char errorname[32]; char errorname[32];
uint16 adverrornum = 0;
extern Zone* zone; extern Zone* zone;
EQStreamFactory eqsf(ZoneStream); EQStreamFactory eqsf(ZoneStream);
npcDecayTimes_Struct npcCorpseDecayTimes[100]; npcDecayTimes_Struct npcCorpseDecayTimes[100];
@ -249,9 +248,6 @@ int main(int argc, char** argv) {
Log.Out(Logs::General, Logs::Zone_Server, "Loading titles"); Log.Out(Logs::General, Logs::Zone_Server, "Loading titles");
title_manager.LoadTitles(); title_manager.LoadTitles();
Log.Out(Logs::General, Logs::Zone_Server, "Loading AA effects");
database.LoadAAEffects();
Log.Out(Logs::General, Logs::Zone_Server, "Loading tributes"); Log.Out(Logs::General, Logs::Zone_Server, "Loading tributes");
database.LoadTributes(); database.LoadTributes();

View File

@ -31,7 +31,6 @@
#include "../common/linked_list.h" #include "../common/linked_list.h"
#include "../common/servertalk.h" #include "../common/servertalk.h"
#include "aa.h"
#include "client.h" #include "client.h"
#include "entity.h" #include "entity.h"
#include "npc.h" #include "npc.h"

View File

@ -4077,33 +4077,7 @@ XS(XS_Client_RefundAA) {
if(THIS == nullptr) if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
int curpt = 0; THIS->RefundAA();
bool refunded = false;
for(int x1=0;x1<aaHighestID;x1++){
curpt = THIS->GetAA(x1);
if(curpt > 0){
SendAA_Struct* curaa = zone->FindAA(x1);
if(curaa){
THIS->SetAA(x1, 0);
for(int x2=0;x2<curpt;x2++){ //add up all the AA points pt by pt to get the correct cost
THIS->GetPP().aapoints += curaa->cost + (curaa->cost_inc * x2);
refunded = true;
}
}
else //aa doesn't exist.. but if they bought it then it had at least a cost of 1 point each
{ //so give back what we can
THIS->GetPP().aapoints += curpt;
THIS->SetAA(x1, 0);
refunded = true;
}
}
}
if(refunded){
THIS->Save(); //save of course
THIS->Kick(); //client gets all buggy if we don't immediatly relog so just force it on them
}
} }
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
@ -4915,11 +4889,44 @@ XS(XS_Client_IncrementAA)
if(THIS == nullptr) if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->IncrementAA(aaskillid); THIS->IncrementAlternateAdvancementRank(aaskillid);
} }
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
XS(XS_Client_GrantAlternateAdvancementAbility); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_GrantAlternateAdvancementAbility)
{
dXSARGS;
if(items < 3 || items > 4)
Perl_croak(aTHX_ "Usage: Client::GrantAlternateAdvancementAbility(THIS, aa_id, points, [ignore_cost])");
{
Client * THIS;
bool RETVAL;
int aa_id = (int)SvIV(ST(1));
int points = (int)SvIV(ST(2));
bool ignore_cost = false;
if(sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Client");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
if(items > 3) {
ignore_cost = (bool)SvTRUE(ST(3));
}
RETVAL = THIS->GrantAlternateAdvancementAbility(aa_id, points, ignore_cost);
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Client_GetAALevel); XS(XS_Client_GetAALevel);
XS(XS_Client_GetAALevel) XS(XS_Client_GetAALevel)
{ {
@ -6463,6 +6470,7 @@ XS(boot_Client)
newXSproto(strcpy(buf, "GetIP"), XS_Client_GetIP, file, "$"); newXSproto(strcpy(buf, "GetIP"), XS_Client_GetIP, file, "$");
newXSproto(strcpy(buf, "AddLevelBasedExp"), XS_Client_AddLevelBasedExp, file, "$$;$"); newXSproto(strcpy(buf, "AddLevelBasedExp"), XS_Client_AddLevelBasedExp, file, "$$;$");
newXSproto(strcpy(buf, "IncrementAA"), XS_Client_IncrementAA, file, "$$"); newXSproto(strcpy(buf, "IncrementAA"), XS_Client_IncrementAA, file, "$$");
newXSproto(strcpy(buf, "GrantAlternateAdvancementAbility"), XS_Client_GrantAlternateAdvancementAbility, file, "$$$;$");
newXSproto(strcpy(buf, "GetAALevel"), XS_Client_GetAALevel, file, "$$"); newXSproto(strcpy(buf, "GetAALevel"), XS_Client_GetAALevel, file, "$$");
newXSproto(strcpy(buf, "MarkCompassLoc"), XS_Client_MarkCompassLoc, file, "$$$$"); newXSproto(strcpy(buf, "MarkCompassLoc"), XS_Client_MarkCompassLoc, file, "$$$$");
newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$"); newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$");

View File

@ -3998,9 +3998,9 @@ XS(XS_Mob_CastSpell)
} }
if (resist_adjust == 0)//If you do not pass resist adjust as nullptr it will ignore the spells default resist adjust if (resist_adjust == 0)//If you do not pass resist adjust as nullptr it will ignore the spells default resist adjust
THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0); THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0);
else else
THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, &resist_adjust); THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, &resist_adjust);
} }
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
@ -6360,12 +6360,12 @@ XS(XS_Mob_GetAA)
{ {
dXSARGS; dXSARGS;
if (items != 2) if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::GetAA(THIS, aa_id)"); Perl_croak(aTHX_ "Usage: Mob::GetAA(THIS, rank_id)");
{ {
Mob * THIS; Mob * THIS;
uint32 RETVAL; uint32 RETVAL;
dXSTARG; dXSTARG;
uint32 aa_id = (uint32)SvUV(ST(1)); uint32 rank_id = (uint32)SvUV(ST(1));
if (sv_derived_from(ST(0), "Mob")) { if (sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0))); IV tmp = SvIV((SV*)SvRV(ST(0)));
@ -6376,12 +6376,68 @@ XS(XS_Mob_GetAA)
if(THIS == nullptr) if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetAA(aa_id); RETVAL = THIS->GetAA(rank_id);
XSprePUSH; PUSHu((UV)RETVAL); XSprePUSH; PUSHu((UV)RETVAL);
} }
XSRETURN(1); XSRETURN(1);
} }
XS(XS_Mob_GetAAByAAID); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetAAByAAID)
{
dXSARGS;
if(items != 2)
Perl_croak(aTHX_ "Usage: Mob::GetAAByAAID(THIS, aa_id)");
{
Mob * THIS;
uint32 RETVAL;
dXSTARG;
uint32 aa_id = (uint32)SvUV(ST(1));
if(sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->GetAAByAAID(aa_id);
XSprePUSH; PUSHu((UV)RETVAL);
}
XSRETURN(1);
}
XS(XS_Mob_SetAA); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_SetAA)
{
dXSARGS;
if(items < 3 || items > 4)
Perl_croak(aTHX_ "Usage: Mob::SetAA(THIS, aa_id, points, [charges])");
{
Mob * THIS;
bool RETVAL;
int aa_id = (int)SvIV(ST(1));
int points = (int)SvIV(ST(2));
int charges = (items == 4) ? (int)SvIV(ST(3)) : 0;
if(sv_derived_from(ST(0), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Mob *, tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Mob");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->SetAA(aa_id, points, charges);
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Mob_DivineAura); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_DivineAura); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_DivineAura) XS(XS_Mob_DivineAura)
{ {
@ -8625,6 +8681,8 @@ XS(boot_Mob)
newXSproto(strcpy(buf, "CheckAggroAmount"), XS_Mob_CheckAggroAmount, file, "$$"); newXSproto(strcpy(buf, "CheckAggroAmount"), XS_Mob_CheckAggroAmount, file, "$$");
newXSproto(strcpy(buf, "CheckHealAggroAmount"), XS_Mob_CheckHealAggroAmount, file, "$$"); newXSproto(strcpy(buf, "CheckHealAggroAmount"), XS_Mob_CheckHealAggroAmount, file, "$$");
newXSproto(strcpy(buf, "GetAA"), XS_Mob_GetAA, file, "$$"); newXSproto(strcpy(buf, "GetAA"), XS_Mob_GetAA, file, "$$");
newXSproto(strcpy(buf, "GetAAByAAID"), XS_Mob_GetAAByAAID, file, "$$");
newXSproto(strcpy(buf, "SetAA"), XS_Mob_SetAA, file, "$$$;$");
newXSproto(strcpy(buf, "DivineAura"), XS_Mob_DivineAura, file, "$"); newXSproto(strcpy(buf, "DivineAura"), XS_Mob_DivineAura, file, "$");
newXSproto(strcpy(buf, "AddFeignMemory"), XS_Mob_AddFeignMemory, file, "$$"); newXSproto(strcpy(buf, "AddFeignMemory"), XS_Mob_AddFeignMemory, file, "$$");
newXSproto(strcpy(buf, "RemoveFromFeignMemory"), XS_Mob_RemoveFromFeignMemory, file, "$$"); newXSproto(strcpy(buf, "RemoveFromFeignMemory"), XS_Mob_RemoveFromFeignMemory, file, "$$");

View File

@ -149,22 +149,19 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
} }
who->AddToHateList(this, hate, 0, false); who->AddToHateList(this, hate, 0, false);
if (max_damage > 0 && aabonuses.SkillAttackProc[0] && aabonuses.SkillAttackProc[1] == skill &&
IsValidSpell(aabonuses.SkillAttackProc[2])) {
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[2], who, 10, 0, -1,
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
}
who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false); who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false);
//Make sure 'this' has not killed the target and 'this' is not dead (Damage shield ect). //Make sure 'this' has not killed the target and 'this' is not dead (Damage shield ect).
if(!GetTarget())return; if(!GetTarget())return;
if (HasDied()) return; if (HasDied()) return;
//[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){
int kb_chance = 25;
kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100;
if (zone->random.Roll(kb_chance))
SpellFinished(904, who, 10, 0, -1, spells[904].ResistDiff);
//who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC.
}
if (HasSkillProcs()) if (HasSkillProcs())
TrySkillProc(who, skill, ReuseTime*1000); TrySkillProc(who, skill, ReuseTime*1000);
@ -2442,19 +2439,18 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
} }
other->AddToHateList(this, hate, 0, false); other->AddToHateList(this, hate, 0, false);
if (damage > 0 && aabonuses.SkillAttackProc[0] && aabonuses.SkillAttackProc[1] == skillinuse &&
IsValidSpell(aabonuses.SkillAttackProc[2])) {
float chance = aabonuses.SkillAttackProc[0] / 1000.0f;
if (zone->random.Roll(chance))
SpellFinished(aabonuses.SkillAttackProc[2], other, 10, 0, -1,
spells[aabonuses.SkillAttackProc[2]].ResistDiff);
}
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse); other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
if (HasDied()) if (HasDied())
return; return;
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skillinuse){
int kb_chance = 25;
kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100;
if (zone->random.Roll(kb_chance))
SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff);
}
if (CanSkillProc && HasSkillProcs()) if (CanSkillProc && HasSkillProcs())
TrySkillProc(other, skillinuse, ReuseTime); TrySkillProc(other, skillinuse, ReuseTime);

File diff suppressed because it is too large Load Diff

View File

@ -146,7 +146,8 @@ void NPC::SpellProcess()
// to allow procs to work // to allow procs to work
bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot,
uint32 timer, uint32 timer_duration, uint32 type, int16 *resist_adjust) uint32 timer, uint32 timer_duration, int16 *resist_adjust,
uint32 aa_id)
{ {
Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d", Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d",
(IsValidSpell(spell_id))?spells[spell_id].name:"UNKNOWN SPELL", spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot); (IsValidSpell(spell_id))?spells[spell_id].name:"UNKNOWN SPELL", spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot);
@ -318,11 +319,11 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
if(resist_adjust) if(resist_adjust)
{ {
return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, type, *resist_adjust)); return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, *resist_adjust, aa_id));
} }
else else
{ {
return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, type, spells[spell_id].ResistDiff)); return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, spells[spell_id].ResistDiff, aa_id));
} }
} }
@ -336,8 +337,8 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
// //
bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish,
uint32 item_slot, uint32 timer, uint32 timer_duration, uint32 type, uint32 item_slot, uint32 timer, uint32 timer_duration,
int16 resist_adjust) int16 resist_adjust, uint32 aa_id)
{ {
Mob* pMob = nullptr; Mob* pMob = nullptr;
int32 orgcasttime; int32 orgcasttime;
@ -361,7 +362,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
casting_spell_timer = timer; casting_spell_timer = timer;
casting_spell_timer_duration = timer_duration; casting_spell_timer_duration = timer_duration;
} }
casting_spell_type = type; casting_spell_aa_id = aa_id;
SaveSpellLoc(); SaveSpellLoc();
Log.Out(Logs::Detail, Logs::Spells, "Casting %d Started at (%.3f,%.3f,%.3f)", spell_id, m_SpellLocation.x, m_SpellLocation.y, m_SpellLocation.z); Log.Out(Logs::Detail, Logs::Spells, "Casting %d Started at (%.3f,%.3f,%.3f)", spell_id, m_SpellLocation.x, m_SpellLocation.y, m_SpellLocation.z);
@ -408,24 +409,19 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
// ok now we know the target // ok now we know the target
casting_spell_targetid = target_id; casting_spell_targetid = target_id;
if (mana_cost == -1) { // We don't get actual mana cost here, that's done when we consume the mana
if (mana_cost == -1)
mana_cost = spell.mana; mana_cost = spell.mana;
mana_cost = GetActSpellCost(spell_id, mana_cost);
}
if(HasMGB() && spells[spell_id].can_mgb)
mana_cost *= 2;
// mana is checked for clients on the frontend. we need to recheck it for NPCs though // mana is checked for clients on the frontend. we need to recheck it for NPCs though
// fix: items dont need mana :-/
// If you're at full mana, let it cast even if you dont have enough mana // If you're at full mana, let it cast even if you dont have enough mana
// we calculated this above, now enforce it // we calculated this above, now enforce it
if(mana_cost > 0 && slot != 10) if(mana_cost > 0 && slot != USE_ITEM_SPELL_SLOT)
{ {
int my_curmana = GetMana(); int my_curmana = GetMana();
int my_maxmana = GetMaxMana(); int my_maxmana = GetMaxMana();
if(my_curmana < spell.mana) // not enough mana if(my_curmana < mana_cost) // not enough mana
{ {
//this is a special case for NPCs with no mana... //this is a special case for NPCs with no mana...
if(IsNPC() && my_curmana == my_maxmana) if(IsNPC() && my_curmana == my_maxmana)
@ -783,9 +779,9 @@ void Mob::ZeroCastingVars()
casting_spell_inventory_slot = 0; casting_spell_inventory_slot = 0;
casting_spell_timer = 0; casting_spell_timer = 0;
casting_spell_timer_duration = 0; casting_spell_timer_duration = 0;
casting_spell_type = 0;
casting_spell_resist_adjust = 0; casting_spell_resist_adjust = 0;
casting_spell_checks = false; casting_spell_checks = false;
casting_spell_aa_id = 0;
delaytimer = false; delaytimer = false;
} }
@ -816,10 +812,9 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot); CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot);
} }
if(casting_spell_type == 1 && IsClient()) { //Rest AA Timer on failed cast if(casting_spell_aa_id && IsClient()) { //Rest AA Timer on failed cast
CastToClient()->SendAATimer(casting_spell_timer - pTimerAAStart, 0, 0xFFFFFF); CastToClient()->Message_StringID(MT_SpellFailure, ABILITY_FAILED);
CastToClient()->Message_StringID(15,ABILITY_FAILED); CastToClient()->ResetAlternateAdvancementTimer(casting_spell_aa_id);
CastToClient()->GetPTimers().Clear(&database, casting_spell_timer);
} }
ZeroCastingVars(); // resets all the state keeping stuff ZeroCastingVars(); // resets all the state keeping stuff
@ -2078,7 +2073,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false, level_override)) { else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false, level_override)) {
if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) { if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
// Prevent mana usage/timers being set for beneficial buffs // Prevent mana usage/timers being set for beneficial buffs
if(casting_spell_type == 1) if(casting_spell_aa_id)
InterruptSpell(); InterruptSpell();
return false; return false;
} }
@ -2157,11 +2152,11 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
} }
#endif //BOTS #endif //BOTS
// We hold off turning MBG off so we can still use it to calc the mana cost
if(spells[spell_id].can_mgb && HasMGB()) if(spells[spell_id].can_mgb && HasMGB())
{ {
SpellOnTarget(spell_id, this); SpellOnTarget(spell_id, this);
entity_list.MassGroupBuff(this, this, spell_id, true); entity_list.MassGroupBuff(this, this, spell_id, true);
SetMGB(false);
} }
else else
{ {
@ -2262,20 +2257,36 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
} }
// if this was a spell slot or an ability use up the mana for it // if this was a spell slot or an ability use up the mana for it
// CastSpell already reduced the cost for it if we're a client with focus
if(slot != USE_ITEM_SPELL_SLOT && slot != POTION_BELT_SPELL_SLOT && slot != TARGET_RING_SPELL_SLOT && mana_used > 0) if(slot != USE_ITEM_SPELL_SLOT && slot != POTION_BELT_SPELL_SLOT && slot != TARGET_RING_SPELL_SLOT && mana_used > 0)
{ {
mana_used = GetActSpellCost(spell_id, mana_used);
if (HasMGB() && spells[spell_id].can_mgb) {
mana_used *= 2;
SetMGB(false);
}
// clamp if we some how got focused above our current mana
if (GetMana() < mana_used)
mana_used = GetMana();
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: consuming %d mana", spell_id, mana_used); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: consuming %d mana", spell_id, mana_used);
if (!DoHPToManaCovert(mana_used)) if (!DoHPToManaCovert(mana_used)) {
SetMana(GetMana() - mana_used); SetMana(GetMana() - mana_used);
TryTriggerOnValueAmount(false, true); TryTriggerOnValueAmount(false, true);
} }
}
//set our reuse timer on long ass reuse_time spells... //set our reuse timer on long ass reuse_time spells...
if(IsClient() && !isproc) if(IsClient() && !isproc)
{ {
if(spell_id == casting_spell_id && casting_spell_timer != 0xFFFFFFFF) if(casting_spell_aa_id) {
AA::Rank *rank = zone->GetAlternateAdvancementRank(casting_spell_aa_id);
if(rank && rank->base_ability) {
ExpendAlternateAdvancementCharge(rank->base_ability->id);
}
}
else if(spell_id == casting_spell_id && casting_spell_timer != 0xFFFFFFFF)
{ {
//aa new todo: aa expendable charges here
CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration); CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration);
Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Setting custom reuse timer %d to %d", spell_id, casting_spell_timer, casting_spell_timer_duration); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Setting custom reuse timer %d to %d", spell_id, casting_spell_timer, casting_spell_timer_duration);
} }
@ -3753,7 +3764,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
// if SpellEffect returned false there's a problem applying the // if SpellEffect returned false there's a problem applying the
// spell. It's most likely a buff that can't stack. // spell. It's most likely a buff that can't stack.
Log.Out(Logs::Detail, Logs::Spells, "Spell %d could not apply its effects %s -> %s\n", spell_id, GetName(), spelltar->GetName()); Log.Out(Logs::Detail, Logs::Spells, "Spell %d could not apply its effects %s -> %s\n", spell_id, GetName(), spelltar->GetName());
if(casting_spell_type != 1) // AA is handled differently if(casting_spell_aa_id)
Message_StringID(MT_SpellFailure, SPELL_NO_HOLD); Message_StringID(MT_SpellFailure, SPELL_NO_HOLD);
safe_delete(action_packet); safe_delete(action_packet);
return false; return false;
@ -4116,8 +4127,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
} }
return true; return true;
} }
else if (CheckAATimer(aaTimerWarcry))
else if (IsClient() && CastToClient()->CheckAAEffect(aaEffectWarcry))
{ {
Message(13, "Your are immune to fear."); Message(13, "Your are immune to fear.");
Log.Out(Logs::Detail, Logs::Spells, "Clients has WarCry effect, immune to fear!"); Log.Out(Logs::Detail, Logs::Spells, "Clients has WarCry effect, immune to fear!");

View File

@ -179,10 +179,10 @@ bool TitleManager::IsClientEligibleForTitle(Client *c, std::vector<TitleEntry>::
if((Title->Class >= 0) && (c->GetBaseClass() != Title->Class)) if((Title->Class >= 0) && (c->GetBaseClass() != Title->Class))
return false; return false;
if((Title->MinAAPoints >= 0) && (c->GetAAPointsSpent() < static_cast<uint32>(Title->MinAAPoints))) if((Title->MinAAPoints >= 0) && (c->GetSpentAA() < static_cast<uint32>(Title->MinAAPoints)))
return false; return false;
if((Title->MaxAAPoints >= 0) && (c->GetAAPointsSpent() > static_cast<uint32>(Title->MaxAAPoints))) if((Title->MaxAAPoints >= 0) && (c->GetSpentAA() > static_cast<uint32>(Title->MaxAAPoints)))
return false; return false;
if(Title->SkillID >= 0) if(Title->SkillID >= 0)

View File

@ -212,7 +212,7 @@ void NPC::UpdateWaypoint(int wp_index)
Log.Out(Logs::Detail, Logs::AI, "Next waypoint %d: (%.3f, %.3f, %.3f, %.3f)", wp_index, m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, m_CurrentWayPoint.w); Log.Out(Logs::Detail, Logs::AI, "Next waypoint %d: (%.3f, %.3f, %.3f, %.3f)", wp_index, m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, m_CurrentWayPoint.w);
//fix up pathing Z //fix up pathing Z
if(zone->HasMap() && RuleB(Map, FixPathingZAtWaypoints)) if(zone->HasMap() && RuleB(Map, FixPathingZAtWaypoints) && !IsBoat())
{ {
if(!RuleB(Watermap, CheckForWaterAtWaypoints) || !zone->HasWaterMap() || if(!RuleB(Watermap, CheckForWaterAtWaypoints) || !zone->HasWaterMap() ||
@ -521,7 +521,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
} }
bool send_update = false; bool send_update = false;
int compare_steps = IsBoat() ? 1 : 20; int compare_steps = 20;
if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) { if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) {
float new_x = m_Position.x + m_TargetV.x*tar_vector; float new_x = m_Position.x + m_TargetV.x*tar_vector;

View File

@ -68,7 +68,6 @@ extern bool staticzone;
extern NetConnection net; extern NetConnection net;
extern PetitionList petition_list; extern PetitionList petition_list;
extern QuestParserCollection* parse; extern QuestParserCollection* parse;
extern uint16 adverrornum;
extern uint32 numclients; extern uint32 numclients;
extern WorldServer worldserver; extern WorldServer worldserver;
extern Zone* zone; extern Zone* zone;
@ -805,8 +804,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
weather_intensity = 0; weather_intensity = 0;
blocked_spells = nullptr; blocked_spells = nullptr;
totalBS = 0; totalBS = 0;
aas = nullptr;
totalAAs = 0;
zone_has_current_time = false; zone_has_current_time = false;
Instance_Shutdown_Timer = nullptr; Instance_Shutdown_Timer = nullptr;
@ -865,16 +862,6 @@ Zone::~Zone() {
safe_delete(qGlobals); safe_delete(qGlobals);
safe_delete_array(adv_data); safe_delete_array(adv_data);
safe_delete_array(map_name); safe_delete_array(map_name);
if(aas != nullptr) {
int r;
for(r = 0; r < totalAAs; r++) {
uchar *data = (uchar *) aas[r];
safe_delete_array(data);
}
safe_delete_array(aas);
}
safe_delete(GuildBanks); safe_delete(GuildBanks);
} }
@ -953,16 +940,12 @@ bool Zone::Init(bool iStaticZone) {
zone->LoadAlternateCurrencies(); zone->LoadAlternateCurrencies();
zone->LoadNPCEmotes(&NPCEmoteList); zone->LoadNPCEmotes(&NPCEmoteList);
//Load AA information LoadAlternateAdvancement();
adverrornum = 500;
LoadAAs();
//Load merchant data //Load merchant data
adverrornum = 501;
zone->GetMerchantDataForZoneLoad(); zone->GetMerchantDataForZoneLoad();
//Load temporary merchant data //Load temporary merchant data
adverrornum = 502;
zone->LoadTempMerchantData(); zone->LoadTempMerchantData();
// Merc data // Merc data
@ -974,7 +957,6 @@ bool Zone::Init(bool iStaticZone) {
if (RuleB(Zone, LevelBasedEXPMods)) if (RuleB(Zone, LevelBasedEXPMods))
zone->LoadLevelEXPMods(); zone->LoadLevelEXPMods();
adverrornum = 503;
petition_list.ClearPetitions(); petition_list.ClearPetitions();
petition_list.ReadDatabase(); petition_list.ReadDatabase();

View File

@ -27,6 +27,7 @@
#include "qglobals.h" #include "qglobals.h"
#include "spawn2.h" #include "spawn2.h"
#include "spawngroup.h" #include "spawngroup.h"
#include "aa_ability.h"
struct ZonePoint struct ZonePoint
{ {
@ -113,11 +114,13 @@ public:
inline const uint32& GetMaxClients() { return pMaxClients; } inline const uint32& GetMaxClients() { return pMaxClients; }
void LoadAAs(); //new AA
int GetTotalAAs() { return totalAAs; } void LoadAlternateAdvancement();
SendAA_Struct* GetAABySequence(uint32 seq) { return aas[seq]; } AA::Ability *GetAlternateAdvancementAbility(int id);
SendAA_Struct* FindAA(uint32 id); AA::Ability *GetAlternateAdvancementAbilityByRank(int rank_id);
uint8 GetTotalAALevels(uint32 skill_id); AA::Rank *GetAlternateAdvancementRank(int rank_id);
std::pair<AA::Ability*, AA::Rank*> GetAlternateAdvancementAbilityAndRank(int id, int points_spent);
void LoadZoneDoors(const char* zone, int16 version); void LoadZoneDoors(const char* zone, int16 version);
bool LoadZoneObjects(); bool LoadZoneObjects();
bool LoadGroundSpawns(); bool LoadGroundSpawns();
@ -193,6 +196,10 @@ public:
char *adv_data; char *adv_data;
bool did_adventure_actions; bool did_adventure_actions;
//new AA
std::unordered_map<int, std::unique_ptr<AA::Ability>> aa_abilities;
std::unordered_map<int, std::unique_ptr<AA::Rank>> aa_ranks;
void DoAdventureCountIncrease(); void DoAdventureCountIncrease();
void DoAdventureAssassinationCountIncrease(); void DoAdventureAssassinationCountIncrease();
void DoAdventureActions(); void DoAdventureActions();
@ -313,9 +320,6 @@ private:
int totalBS; int totalBS;
ZoneSpellsBlocked *blocked_spells; ZoneSpellsBlocked *blocked_spells;
int totalAAs;
SendAA_Struct **aas; //array of AA structs
/* /*
Spawn related things Spawn related things
*/ */

View File

@ -6,6 +6,7 @@
#include "position.h" #include "position.h"
#include "../common/faction.h" #include "../common/faction.h"
#include "../common/eqemu_logsys.h" #include "../common/eqemu_logsys.h"
#include "aa_ability.h"
class Client; class Client;
class Corpse; class Corpse;
@ -339,17 +340,10 @@ public:
bool SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list); // needed for factions Dec, 16 2001 bool SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list); // needed for factions Dec, 16 2001
bool LoadFactionData(); bool LoadFactionData();
/* AAs */ /* AAs New */
bool LoadAAEffects(); bool LoadAlternateAdvancementAbilities(std::unordered_map<int, std::unique_ptr<AA::Ability>> &abilities,
bool LoadAAEffects2(); std::unordered_map<int, std::unique_ptr<AA::Rank>> &ranks);
bool LoadSwarmSpells(); bool LoadAlternateAdvancement(Client *c);
SendAA_Struct*GetAASkillVars(uint32 skill_id);
uint8 GetTotalAALevels(uint32 skill_id);
uint32 GetSizeAA();
uint32 CountAAs();
void LoadAAs(SendAA_Struct **load);
uint32 CountAAEffects();
void FillAAEffects(SendAA_Struct* aa_struct);
/* Zone related */ /* Zone related */
bool GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, uint8 &zone_type, int &ruleset, char **map_filename); bool GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, uint8 &zone_type, int &ruleset, char **map_filename);