mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 05:21:29 +00:00
Merge from master
This commit is contained in:
commit
9f1f36cca6
@ -1,5 +1,46 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 07/06/2015 ==
|
||||
mackal: Implement Triple Attack Skill
|
||||
Parses showed about rand(1000) for the chance, may need more investigating
|
||||
Corrected Double Attack chances as well
|
||||
Running optional 2015_07_06_TripleAttack.sql will set current toons to their max skill
|
||||
This is optional because the admins might want to go a different route.
|
||||
|
||||
== 07/05/2015 ==
|
||||
mackal: Rewrite NPC combat attack round logic
|
||||
An NPC "quading" is really just an NPC with innate dual wield that doubles on both hands
|
||||
The old rules allowed NPCs to hit 6 times in one round
|
||||
NPCs also seem to have their own skill progression for DW/DA
|
||||
See: http://www.eqemulator.org/forums/showthread.php?t=38708
|
||||
You can set Combat:UseLiveCombatRounds to false to use the old rules
|
||||
PC Double Attack rates kind of follow the same thing but still needs to be implemented
|
||||
Kinglykrab: WARNING: summonburriedplayercorpse is now summonburiedplayercorpse, getplayerburriedcorpsecount is now getplayerburiedcorpsecount, summon_burried_player_corpse is now summon_buried_player_corpse, and get_player_burried_corpse_count is now get_player_buried_corpse_count FIX THESE IN YOUR SCRIPTS OR THEY WILL NOT WORK!!!!
|
||||
Added bot saylinks (thanks Uleat!)
|
||||
Command aliases for #augmentitem (#aug), #findnpctype (#fn), #findspell (#fs)
|
||||
Bot command changes: #bot sow -> #bot speed, #bot magepet -> #bot setpet, #bot resurrectme -> #bot resurrect
|
||||
Changed all occurrences of burried to buried in the code.
|
||||
client_packet.cpp was referencing old columns in character_corpses, not sure how we didn't already see this before.
|
||||
|
||||
== 7/4/2015 ==
|
||||
mackal: Reworked the activated avoidace skills (riposte, dodge, etc) based on dev quotes
|
||||
This also fixes the order things are checked (avoidance skills, THEN hit/miss)
|
||||
Also riposte immunity from the increase riposte chance spell effect.
|
||||
|
||||
== 7/2/2015 ==
|
||||
KLS/Demonstar55: AA system has been rewritten fixing a ton of bugs and extending functionality while making it easier to create new AA points.
|
||||
KLS/Demonstar55: New tables are needed and so older data will need to be migrated to the new system.
|
||||
KLS/Demonstar55: The SQL saves the old aa points spent/avail/character_alt_abilities data if any server ops want to do something different than PEQ did with it.
|
||||
KLS/Demonstar55: Will try to get a wiki entry written up next week some time explaining the system but it's really not hard to follow the db tables in the meantime.
|
||||
|
||||
== 7/1/2015 ==
|
||||
Akkadius: Fix an issue where emote messages would overflow the buffer of 256 by increasing the size and changing some of the initialization
|
||||
Akkadius: Added a custom Health Update message that will display in the middle of the players screen, to enable this server wide you must enable rule 'Character:MarqueeHPUpdates'
|
||||
Example: https://www.youtube.com/watch?v=KUVdbPxLIn0
|
||||
Akkadius: (Haynar) Fixed some runspeed issues with Perl and LUA scripts
|
||||
Akkadius: (Haynar) Updated #showstats and #npcstats for new speed calcs to display speeds again in familiar float format.
|
||||
Akkadius: (Haynar) Improved client movement while AI Controlled, such as feared and charmed. Movement will be much smoother from clients perspective.
|
||||
|
||||
== 06/12/2015 ==
|
||||
Uleat: Adjusted SessionStats to better reflect a sister implementation
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -1384,7 +1384,7 @@ bool Database::MoveCharacterToZone(const char* charname, const char* zonename) {
|
||||
}
|
||||
|
||||
bool Database::MoveCharacterToZone(uint32 iCharID, const char* iZonename) {
|
||||
std::string query = StringFormat("UPDATE `character_data` SET `zone_id` = %i, `x` = -1, `y` = -1, `z` = -1 WHERE `id` = %i", iZonename, GetZoneID(iZonename), iCharID);
|
||||
std::string query = StringFormat("UPDATE `character_data` SET `zone_id` = %i, `x` = -1, `y` = -1, `z` = -1 WHERE `id` = %i", GetZoneID(iZonename), iCharID);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
|
||||
@ -548,4 +548,5 @@ N(OP_ZoneServerInfo),
|
||||
N(OP_ZoneServerReady),
|
||||
N(OP_ZoneSpawns),
|
||||
N(OP_ZoneUnavail),
|
||||
N(OP_ResetAA),
|
||||
// mail and chat opcodes located in ../mail_oplist.h
|
||||
|
||||
@ -4219,6 +4219,52 @@ struct UseAA_Struct {
|
||||
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 {
|
||||
/*00*/ uint32 skill_id;
|
||||
/*04*/ uint32 base1;
|
||||
@ -4273,7 +4319,7 @@ struct SendAA_Struct {
|
||||
struct AA_Action {
|
||||
/*00*/ uint32 action;
|
||||
/*04*/ uint32 ability;
|
||||
/*08*/ uint32 unknown08;
|
||||
/*08*/ uint32 target_id;
|
||||
/*12*/ uint32 exp_value;
|
||||
};
|
||||
|
||||
|
||||
@ -867,7 +867,7 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) {
|
||||
//factored out so I dont have to copy this crap.
|
||||
#ifdef BOTS
|
||||
#define GuildMemberBaseQuery \
|
||||
"SELECT c.id,c.name,c.class,c.level,c.timelaston,c.zoneid," \
|
||||
"SELECT c.id,c.name,c.class,c.level,c.last_login,c.zone_id," \
|
||||
" g.guild_id,g.rank,g.tribute_enable,g.total_tribute,g.last_tribute," \
|
||||
" g.banker,g.public_note,g.alt" \
|
||||
" FROM vwBotCharacterMobs AS c LEFT JOIN vwGuildMembers AS g ON c.id=g.char_id AND c.mobtype = g.mobtype "
|
||||
|
||||
@ -146,6 +146,7 @@ INr(OP_GuildDelete); //?
|
||||
IN(OP_GuildPublicNote, GuildUpdate_PublicNote);
|
||||
INz(OP_GetGuildsList); //?
|
||||
IN(OP_SetGuildMOTD, GuildMOTD_Struct);
|
||||
IN(OP_SetRunMode, SetRunMode_Struct);
|
||||
INz(OP_GuildPeace); //?
|
||||
INz(OP_GuildWar); //?
|
||||
IN(OP_GuildLeader, GuildMakeLeader);
|
||||
|
||||
@ -2810,7 +2810,7 @@ namespace RoF
|
||||
|
||||
eq->aa_spent = emu->aa_spent;
|
||||
// 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_archetype = 0;
|
||||
eq->aa_spent_class = 0;
|
||||
@ -2846,58 +2846,81 @@ namespace RoF
|
||||
|
||||
ENCODE(OP_SendAATable)
|
||||
{
|
||||
ENCODE_LENGTH_ATLEAST(SendAA_Struct);
|
||||
SETUP_VAR_ENCODE(SendAA_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability));
|
||||
EQApplicationPacket *inapp = *p;
|
||||
*p = nullptr;
|
||||
AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
|
||||
|
||||
// Check clientver field to verify this AA should be sent for SoF
|
||||
// clientver 1 is for all clients and 5 is for Live
|
||||
if (emu->clientver <= 7)
|
||||
{
|
||||
OUT(id);
|
||||
eq->unknown004 = 1;
|
||||
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->title_sid = emu->id - emu->current_level + 1;
|
||||
//eq->desc_sid = emu->id - emu->current_level + 1;
|
||||
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? -1 : (emu->sof_next_skill);
|
||||
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);
|
||||
}
|
||||
// the structs::SendAA_Struct includes enough space for 1 prereq which is the min even if it has no prereqs
|
||||
auto prereq_size = emu->total_prereqs > 1 ? (emu->total_prereqs - 1) * 8 : 0;
|
||||
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));
|
||||
|
||||
|
||||
std::vector<int32> skill;
|
||||
std::vector<int32> points;
|
||||
for(auto i = 0; i < emu->total_prereqs; ++i) {
|
||||
skill.push_back(inapp->ReadUInt32());
|
||||
points.push_back(inapp->ReadUInt32());
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@ -2466,7 +2466,8 @@ namespace RoF2
|
||||
outapp->WriteUInt32(emu->lastlogin);
|
||||
outapp->WriteUInt32(emu->timePlayedMin);
|
||||
outapp->WriteUInt32(emu->timeentitledonaccount);
|
||||
outapp->WriteUInt32(0x0007ffff); // Expansion bitmask
|
||||
outapp->WriteUInt32(emu->expansions);
|
||||
//outapp->WriteUInt32(0x0007ffff); // Expansion bitmask
|
||||
|
||||
outapp->WriteUInt32(structs::MAX_PP_LANGUAGE);
|
||||
|
||||
@ -2899,7 +2900,7 @@ namespace RoF2
|
||||
|
||||
eq->aa_spent = emu->aa_spent;
|
||||
// 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_archetype = 0;
|
||||
eq->aa_spent_class = 0;
|
||||
@ -2935,58 +2936,80 @@ namespace RoF2
|
||||
|
||||
ENCODE(OP_SendAATable)
|
||||
{
|
||||
ENCODE_LENGTH_ATLEAST(SendAA_Struct);
|
||||
SETUP_VAR_ENCODE(SendAA_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability));
|
||||
EQApplicationPacket *inapp = *p;
|
||||
*p = nullptr;
|
||||
AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
|
||||
|
||||
// Check clientver field to verify this AA should be sent for SoF
|
||||
// clientver 1 is for all clients and 5 is for Live
|
||||
if (emu->clientver <= 8)
|
||||
{
|
||||
OUT(id);
|
||||
eq->unknown004 = 1;
|
||||
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->title_sid = emu->id - emu->current_level + 1;
|
||||
//eq->desc_sid = emu->id - emu->current_level + 1;
|
||||
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? -1 : (emu->sof_next_skill);
|
||||
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);
|
||||
}
|
||||
// the structs::SendAA_Struct includes enough space for 1 prereq which is the min even if it has no prereqs
|
||||
auto prereq_size = emu->total_prereqs > 1 ? (emu->total_prereqs - 1) * 8 : 0;
|
||||
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));
|
||||
|
||||
|
||||
std::vector<int32> skill;
|
||||
std::vector<int32> points;
|
||||
for(auto i = 0; i < emu->total_prereqs; ++i) {
|
||||
skill.push_back(inapp->ReadUInt32());
|
||||
points.push_back(inapp->ReadUInt32());
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@ -4289,7 +4289,7 @@ struct AA_List {
|
||||
struct AA_Action {
|
||||
/*00*/ uint32 action;
|
||||
/*04*/ uint32 ability;
|
||||
/*08*/ uint32 unknown08;
|
||||
/*08*/ uint32 target_id;
|
||||
/*12*/ uint32 exp_value;
|
||||
/*16*/
|
||||
};
|
||||
|
||||
@ -4288,7 +4288,7 @@ struct AA_List {
|
||||
struct AA_Action {
|
||||
/*00*/ uint32 action;
|
||||
/*04*/ uint32 ability;
|
||||
/*08*/ uint32 unknown08;
|
||||
/*08*/ uint32 target_id;
|
||||
/*12*/ uint32 exp_value;
|
||||
/*16*/
|
||||
};
|
||||
|
||||
@ -1677,8 +1677,8 @@ namespace SoD
|
||||
OUT(copper_bank);
|
||||
OUT(platinum_shared);
|
||||
// OUT(unknown13156[84]);
|
||||
//OUT(expansions);
|
||||
eq->expansions = 16383;
|
||||
OUT(expansions);
|
||||
//eq->expansions = 16383;
|
||||
// OUT(unknown13244[12]);
|
||||
OUT(autosplit);
|
||||
// OUT(unknown13260[16]);
|
||||
@ -1862,55 +1862,56 @@ namespace SoD
|
||||
|
||||
ENCODE(OP_SendAATable)
|
||||
{
|
||||
ENCODE_LENGTH_ATLEAST(SendAA_Struct);
|
||||
SETUP_VAR_ENCODE(SendAA_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability));
|
||||
EQApplicationPacket *inapp = *p;
|
||||
*p = nullptr;
|
||||
AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
|
||||
|
||||
// Check clientver field to verify this AA should be sent for SoF
|
||||
// clientver 1 is for all clients and 5 is for SoD
|
||||
if (emu->clientver <= 5)
|
||||
{
|
||||
OUT(id);
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
|
||||
structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
|
||||
|
||||
inapp->SetReadPosition(sizeof(AARankInfo_Struct));
|
||||
outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
|
||||
|
||||
eq->id = emu->id;
|
||||
eq->unknown004 = 1;
|
||||
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->title_sid = emu->id - emu->current_level + 1;
|
||||
//eq->desc_sid = emu->id - emu->current_level + 1;
|
||||
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill);
|
||||
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (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);
|
||||
OUT(prereq_skill);
|
||||
OUT(prereq_minpoints);
|
||||
eq->type = emu->sof_type;
|
||||
OUT(spellid);
|
||||
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);
|
||||
}
|
||||
eq->id = emu->id;
|
||||
eq->hotkey_sid = emu->upper_hotkey_sid;
|
||||
eq->hotkey_sid2 = emu->lower_hotkey_sid;
|
||||
eq->desc_sid = emu->desc_sid;
|
||||
eq->title_sid = emu->title_sid;
|
||||
eq->class_type = emu->level_req;
|
||||
eq->cost = emu->cost;
|
||||
eq->seq = emu->seq;
|
||||
eq->current_level = emu->current_level;
|
||||
eq->type = emu->type;
|
||||
eq->spellid = emu->spell;
|
||||
eq->spell_type = emu->spell_type;
|
||||
eq->spell_refresh = emu->spell_refresh;
|
||||
eq->classes = emu->classes;
|
||||
eq->max_level = emu->max_level;
|
||||
eq->last_id = emu->prev_id;
|
||||
eq->next_id = emu->next_id;
|
||||
eq->cost2 = emu->total_cost;
|
||||
eq->grant_only = emu->grant_only;
|
||||
eq->expendable_charges = emu->charges;
|
||||
eq->aa_expansion = emu->expansion;
|
||||
eq->special_category = emu->category;
|
||||
eq->total_abilities = emu->total_effects;
|
||||
|
||||
for(auto i = 0; i < eq->total_abilities; ++i) {
|
||||
eq->abilities[i].skill_id = inapp->ReadUInt32();
|
||||
eq->abilities[i].base1 = inapp->ReadUInt32();
|
||||
eq->abilities[i].base2 = inapp->ReadUInt32();
|
||||
eq->abilities[i].slot = inapp->ReadUInt32();
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@ -3813,8 +3813,7 @@ struct SendAA_Struct {
|
||||
/*0049*/ uint32 spellid;
|
||||
/*0053*/ uint32 spell_type;
|
||||
/*0057*/ uint32 spell_refresh;
|
||||
/*0061*/ uint16 classes;
|
||||
/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability
|
||||
/*0061*/ uint32 classes;
|
||||
/*0065*/ uint32 max_level;
|
||||
/*0069*/ uint32 last_id;
|
||||
/*0073*/ uint32 next_id;
|
||||
@ -3840,7 +3839,7 @@ struct AA_List {
|
||||
struct AA_Action {
|
||||
/*00*/ uint32 action;
|
||||
/*04*/ uint32 ability;
|
||||
/*08*/ uint32 unknown08;
|
||||
/*08*/ uint32 target_id;
|
||||
/*12*/ uint32 exp_value;
|
||||
};
|
||||
|
||||
|
||||
@ -1335,8 +1335,8 @@ namespace SoF
|
||||
OUT(copper_bank);
|
||||
OUT(platinum_shared);
|
||||
// OUT(unknown13156[84]);
|
||||
//OUT(expansions);
|
||||
eq->expansions = 16383;
|
||||
OUT(expansions);
|
||||
//eq->expansions = 16383;
|
||||
// OUT(unknown13244[12]);
|
||||
OUT(autosplit);
|
||||
// OUT(unknown13260[16]);
|
||||
@ -1520,56 +1520,56 @@ namespace SoF
|
||||
|
||||
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);
|
||||
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability));
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
|
||||
structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
|
||||
|
||||
// Check clientver field to verify this AA should be sent for SoF
|
||||
// clientver 1 is for all clients and 4 is for SoF
|
||||
if (emu->clientver <= 4)
|
||||
{
|
||||
OUT(id);
|
||||
inapp->SetReadPosition(sizeof(AARankInfo_Struct));
|
||||
outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
|
||||
|
||||
eq->id = emu->id;
|
||||
eq->unknown004 = 1;
|
||||
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->title_sid = emu->id - emu->current_level + 1;
|
||||
//eq->desc_sid = emu->id - emu->current_level + 1;
|
||||
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill);
|
||||
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (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);
|
||||
OUT(prereq_skill);
|
||||
OUT(prereq_minpoints);
|
||||
eq->type = emu->sof_type;
|
||||
OUT(spellid);
|
||||
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);
|
||||
}
|
||||
eq->id = emu->id;
|
||||
eq->hotkey_sid = emu->upper_hotkey_sid;
|
||||
eq->hotkey_sid2 = emu->lower_hotkey_sid;
|
||||
eq->desc_sid = emu->desc_sid;
|
||||
eq->title_sid = emu->title_sid;
|
||||
eq->class_type = emu->level_req;
|
||||
eq->cost = emu->cost;
|
||||
eq->seq = emu->seq;
|
||||
eq->current_level = emu->current_level;
|
||||
eq->type = emu->type;
|
||||
eq->spellid = emu->spell;
|
||||
eq->spell_type = emu->spell_type;
|
||||
eq->spell_refresh = emu->spell_refresh;
|
||||
eq->classes = emu->classes;
|
||||
eq->max_level = emu->max_level;
|
||||
eq->last_id = emu->prev_id;
|
||||
eq->next_id = emu->next_id;
|
||||
eq->cost2 = emu->total_cost;
|
||||
eq->grant_only = emu->grant_only;
|
||||
eq->expendable_charges = emu->charges;
|
||||
eq->aa_expansion = emu->expansion;
|
||||
eq->special_category = emu->category;
|
||||
eq->total_abilities = emu->total_effects;
|
||||
|
||||
for(auto i = 0; i < eq->total_abilities; ++i) {
|
||||
eq->abilities[i].skill_id = inapp->ReadUInt32();
|
||||
eq->abilities[i].base1 = inapp->ReadUInt32();
|
||||
eq->abilities[i].base2 = inapp->ReadUInt32();
|
||||
eq->abilities[i].slot = inapp->ReadUInt32();
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1665,8 +1665,6 @@ namespace SoF
|
||||
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||
}
|
||||
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
//hack hack hack
|
||||
|
||||
@ -3677,8 +3677,7 @@ struct SendAA_Struct {
|
||||
/*0049*/ uint32 spellid;
|
||||
/*0053*/ uint32 spell_type;
|
||||
/*0057*/ uint32 spell_refresh;
|
||||
/*0061*/ uint16 classes;
|
||||
/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability
|
||||
/*0061*/ uint32 classes;
|
||||
/*0065*/ uint32 max_level;
|
||||
/*0069*/ uint32 last_id;
|
||||
/*0073*/ uint32 next_id;
|
||||
@ -3702,7 +3701,7 @@ struct AA_List {
|
||||
struct AA_Action {
|
||||
/*00*/ uint32 action;
|
||||
/*04*/ uint32 ability;
|
||||
/*08*/ uint32 unknown08;
|
||||
/*08*/ uint32 target_id;
|
||||
/*12*/ uint32 exp_value;
|
||||
};
|
||||
|
||||
|
||||
@ -1107,50 +1107,52 @@ namespace Titanium
|
||||
|
||||
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);
|
||||
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability));
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
|
||||
structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
|
||||
|
||||
// Check clientver field to verify this AA should be sent for Titanium
|
||||
// clientver 1 is for all clients and 3 is for Titanium
|
||||
if (emu->clientver <= 3)
|
||||
{
|
||||
OUT(id);
|
||||
inapp->SetReadPosition(sizeof(AARankInfo_Struct));
|
||||
outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
|
||||
|
||||
eq->id = emu->id;
|
||||
eq->unknown004 = 1;
|
||||
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1);
|
||||
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1);
|
||||
eq->title_sid = emu->id - emu->current_level + 1;
|
||||
eq->desc_sid = emu->id - emu->current_level + 1;
|
||||
OUT(class_type);
|
||||
OUT(cost);
|
||||
OUT(seq);
|
||||
OUT(current_level);
|
||||
OUT(prereq_skill);
|
||||
OUT(prereq_minpoints);
|
||||
OUT(type);
|
||||
OUT(spellid);
|
||||
OUT(spell_type);
|
||||
OUT(spell_refresh);
|
||||
OUT(classes);
|
||||
OUT(berserker);
|
||||
OUT(max_level);
|
||||
OUT(last_id);
|
||||
OUT(next_id);
|
||||
OUT(cost2);
|
||||
OUT(unknown80[0]);
|
||||
OUT(unknown80[1]);
|
||||
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);
|
||||
}
|
||||
eq->id = emu->id;
|
||||
eq->hotkey_sid = emu->upper_hotkey_sid;
|
||||
eq->hotkey_sid2 = emu->lower_hotkey_sid;
|
||||
eq->desc_sid = emu->desc_sid;
|
||||
eq->title_sid = emu->title_sid;
|
||||
eq->class_type = emu->level_req;
|
||||
eq->cost = emu->cost;
|
||||
eq->seq = emu->seq;
|
||||
eq->current_level = emu->current_level;
|
||||
eq->type = emu->type;
|
||||
eq->spellid = emu->spell;
|
||||
eq->spell_type = emu->spell_type;
|
||||
eq->spell_refresh = emu->spell_refresh;
|
||||
eq->classes = emu->classes;
|
||||
eq->max_level = emu->max_level;
|
||||
eq->last_id = emu->prev_id;
|
||||
eq->next_id = emu->next_id;
|
||||
eq->cost2 = emu->total_cost;
|
||||
eq->total_abilities = emu->total_effects;
|
||||
|
||||
for(auto i = 0; i < eq->total_abilities; ++i) {
|
||||
eq->abilities[i].skill_id = inapp->ReadUInt32();
|
||||
eq->abilities[i].base1 = inapp->ReadUInt32();
|
||||
eq->abilities[i].base2 = inapp->ReadUInt32();
|
||||
eq->abilities[i].slot = inapp->ReadUInt32();
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@ -3157,8 +3157,7 @@ struct SendAA_Struct {
|
||||
/*0052*/ uint32 spellid;
|
||||
/*0056*/ uint32 spell_type;
|
||||
/*0060*/ uint32 spell_refresh;
|
||||
/*0064*/ uint16 classes;
|
||||
/*0066*/ uint16 berserker; //seems to be 1 if its a berserker ability
|
||||
/*0064*/ uint32 classes;
|
||||
/*0068*/ uint32 max_level;
|
||||
/*0072*/ uint32 last_id;
|
||||
/*0076*/ uint32 next_id;
|
||||
@ -3175,7 +3174,7 @@ struct AA_List {
|
||||
struct AA_Action {
|
||||
/*00*/ uint32 action;
|
||||
/*04*/ uint32 ability;
|
||||
/*08*/ uint32 unknown08;
|
||||
/*08*/ uint32 target_id;
|
||||
/*12*/ uint32 exp_value;
|
||||
};
|
||||
|
||||
|
||||
@ -1805,11 +1805,13 @@ namespace UF
|
||||
//NOTE: new client supports 300 AAs, our internal rep/PP
|
||||
//only supports 240..
|
||||
for (r = 0; r < MAX_PP_AA_ARRAY; r++) {
|
||||
OUT(aa_array[r].AA);
|
||||
OUT(aa_array[r].value);
|
||||
OUT(aa_array[r].charges);
|
||||
eq->aa_array[r].AA = emu->aa_array[r].AA;
|
||||
eq->aa_array[r].value = emu->aa_array[r].value;
|
||||
eq->aa_array[r].charges = emu->aa_array[r].charges;
|
||||
}
|
||||
|
||||
// OUT(unknown02220[4]);
|
||||
|
||||
OUT(mana);
|
||||
OUT(cur_hp);
|
||||
OUT(STR);
|
||||
@ -1939,8 +1941,8 @@ namespace UF
|
||||
OUT(copper_bank);
|
||||
OUT(platinum_shared);
|
||||
// OUT(unknown13156[84]);
|
||||
//OUT(expansions);
|
||||
eq->expansions = 0xffff;
|
||||
OUT(expansions);
|
||||
//eq->expansions = 0x1ffff;
|
||||
// OUT(unknown13244[12]);
|
||||
OUT(autosplit);
|
||||
// OUT(unknown13260[16]);
|
||||
@ -2128,7 +2130,7 @@ namespace UF
|
||||
|
||||
eq->aa_spent = emu->aa_spent;
|
||||
eq->aa_assigned = emu->aa_spent;
|
||||
eq->aa_spent3 = emu->aa_spent;
|
||||
eq->aa_spent3 = 0;
|
||||
eq->unknown012 = 0;
|
||||
eq->unknown016 = 0;
|
||||
eq->unknown020 = 0;
|
||||
@ -2145,55 +2147,56 @@ namespace UF
|
||||
|
||||
ENCODE(OP_SendAATable)
|
||||
{
|
||||
ENCODE_LENGTH_ATLEAST(SendAA_Struct);
|
||||
SETUP_VAR_ENCODE(SendAA_Struct);
|
||||
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability));
|
||||
EQApplicationPacket *inapp = *p;
|
||||
*p = nullptr;
|
||||
AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer;
|
||||
|
||||
// Check clientver field to verify this AA should be sent for SoF
|
||||
// clientver 1 is for all clients and 6 is for Underfoot
|
||||
if (emu->clientver <= 6)
|
||||
{
|
||||
OUT(id);
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability));
|
||||
structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer;
|
||||
|
||||
inapp->SetReadPosition(sizeof(AARankInfo_Struct));
|
||||
outapp->SetWritePosition(sizeof(structs::SendAA_Struct));
|
||||
|
||||
eq->id = emu->id;
|
||||
eq->unknown004 = 1;
|
||||
//eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1);
|
||||
//eq->title_sid = emu->id - emu->current_level + 1;
|
||||
//eq->desc_sid = emu->id - emu->current_level + 1;
|
||||
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill);
|
||||
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (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);
|
||||
OUT(prereq_skill);
|
||||
OUT(prereq_minpoints);
|
||||
eq->type = emu->sof_type;
|
||||
OUT(spellid);
|
||||
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);
|
||||
}
|
||||
eq->id = emu->id;
|
||||
eq->hotkey_sid = emu->upper_hotkey_sid;
|
||||
eq->hotkey_sid2 = emu->lower_hotkey_sid;
|
||||
eq->desc_sid = emu->desc_sid;
|
||||
eq->title_sid = emu->title_sid;
|
||||
eq->class_type = emu->level_req;
|
||||
eq->cost = emu->cost;
|
||||
eq->seq = emu->seq;
|
||||
eq->current_level = emu->current_level;
|
||||
eq->type = emu->type;
|
||||
eq->spellid = emu->spell;
|
||||
eq->spell_type = emu->spell_type;
|
||||
eq->spell_refresh = emu->spell_refresh;
|
||||
eq->classes = emu->classes;
|
||||
eq->max_level = emu->max_level;
|
||||
eq->last_id = emu->prev_id;
|
||||
eq->next_id = emu->next_id;
|
||||
eq->cost2 = emu->total_cost;
|
||||
eq->grant_only = emu->grant_only;
|
||||
eq->expendable_charges = emu->charges;
|
||||
eq->aa_expansion = emu->expansion;
|
||||
eq->special_category = emu->category;
|
||||
eq->total_abilities = emu->total_effects;
|
||||
|
||||
for(auto i = 0; i < eq->total_abilities; ++i) {
|
||||
eq->abilities[i].skill_id = inapp->ReadUInt32();
|
||||
eq->abilities[i].base1 = inapp->ReadUInt32();
|
||||
eq->abilities[i].base2 = inapp->ReadUInt32();
|
||||
eq->abilities[i].slot = inapp->ReadUInt32();
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@ -3886,8 +3886,7 @@ struct SendAA_Struct {
|
||||
/*0049*/ uint32 spellid;
|
||||
/*0053*/ uint32 spell_type;
|
||||
/*0057*/ uint32 spell_refresh;
|
||||
/*0061*/ uint16 classes;
|
||||
/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability
|
||||
/*0061*/ uint32 classes;
|
||||
/*0065*/ uint32 max_level;
|
||||
/*0069*/ uint32 last_id;
|
||||
/*0073*/ uint32 next_id;
|
||||
@ -3913,7 +3912,7 @@ struct AA_List {
|
||||
struct AA_Action {
|
||||
/*00*/ uint32 action;
|
||||
/*04*/ uint32 ability;
|
||||
/*08*/ uint32 unknown08;
|
||||
/*08*/ uint32 target_id;
|
||||
/*12*/ uint32 exp_value;
|
||||
};
|
||||
|
||||
|
||||
@ -139,8 +139,4 @@ protected:
|
||||
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
|
||||
|
||||
@ -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_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_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, OrnamentationAugmentType, 20) //Ornamentation Augment Type
|
||||
RULE_REAL(Character, EnvironmentDamageMulipliter, 1)
|
||||
@ -113,6 +114,8 @@ RULE_INT(Character, TradeskillUpMakePoison, 2) // Make Poison skillup rate adjus
|
||||
RULE_INT(Character, TradeskillUpPottery, 4) // Pottery skillup rate adjust. Lower is faster.
|
||||
RULE_INT(Character, TradeskillUpResearch, 1) // Research skillup rate adjust. Lower is faster.
|
||||
RULE_INT(Character, TradeskillUpTinkering, 2) // Tinkering skillup rate adjust. Lower is faster.
|
||||
RULE_BOOL(Character, SpamHPUpdates, false) // if your server has stupid amounts of HP that causes client display issues, turn this on!
|
||||
RULE_BOOL(Character, MarqueeHPUpdates, false) // Will show Health % in center of screen < 100%
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@ -183,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, TitaniumStartZoneID, -1) //Sets the Starting Zone for Titanium Clients (-1 is disabled). Replaces the old method.
|
||||
RULE_INT(World, ExpansionSettings, 16383) // Sets the expansion settings for the server, This is sent on login to world and affects client expansion settings. Defaults to all expansions enabled up to TSS.
|
||||
RULE_BOOL(World, UseClientBasedExpansionSettings, true) // if true it will overrule World, ExpansionSettings and set someone's expansion based on the client they're using
|
||||
RULE_INT(World, PVPSettings, 0) // Sets the PVP settings for the server, 1 = Rallos Zek RuleSet, 2 = Tallon/Vallon Zek Ruleset, 4 = Sullon Zek Ruleset, 6 = Discord Ruleset, anything above 6 is the Discord Ruleset without the no-drop restrictions removed. TODO: Edit IsAttackAllowed in Zone to accomodate for these rules.
|
||||
RULE_BOOL (World, IsGMPetitionWindowEnabled, false)
|
||||
RULE_INT (World, FVNoDropFlag, 0) // Sets the Firiona Vie settings on the client. If set to 2, the flag will be set for GMs only, allowing trading of no-drop items.
|
||||
@ -444,6 +448,7 @@ RULE_BOOL(Combat, OneProcPerWeapon, true) //If enabled, One proc per weapon per
|
||||
RULE_BOOL(Combat, ProjectileDmgOnImpact, true) //If enabled, projectiles (ie arrows) will hit on impact, instead of instantly.
|
||||
RULE_BOOL(Combat, MeleePush, true) // enable melee push
|
||||
RULE_INT(Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed. Made up, 100 actually isn't that bad
|
||||
RULE_BOOL(Combat, UseLiveCombatRounds, true) // turn this false if you don't want to worry about fixing up combat rounds for NPCs
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(NPC)
|
||||
@ -501,6 +506,8 @@ RULE_INT(Bots, BotAAExpansion, 8) // Bots get AAs through this expansion
|
||||
RULE_BOOL(Bots, BotGroupXP, false) // Determines whether client gets xp for bots outside their group.
|
||||
RULE_BOOL(Bots, BotBardUseOutOfCombatSongs, true) // Determines whether bard bots use additional out of combat songs.
|
||||
RULE_BOOL(Bots, BotLevelsWithOwner, false) // Auto-updates spawned bots as owner levels/de-levels (false is original behavior)
|
||||
RULE_BOOL(Bots, BotCharacterLevelEnabled, false) // Enables required level to spawn bots
|
||||
RULE_INT(Bots, BotCharacterLevel, 0) // 0 as default (if level > this value you can spawn bots if BotCharacterLevelEnabled is true)
|
||||
RULE_CATEGORY_END()
|
||||
#endif
|
||||
|
||||
|
||||
@ -761,6 +761,7 @@ typedef enum {
|
||||
struct LauncherZoneRequest {
|
||||
uint8 command;
|
||||
char short_name[33];
|
||||
uint16 port;
|
||||
};
|
||||
|
||||
struct LauncherZoneStatus {
|
||||
|
||||
@ -1662,6 +1662,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
sp[tempid].not_extendable = atoi(row[197]) != 0;
|
||||
sp[tempid].suspendable = atoi(row[200]) != 0;
|
||||
sp[tempid].viral_range = atoi(row[201]);
|
||||
sp[tempid].songcap = atoi(row[202]);
|
||||
sp[tempid].no_block = atoi(row[205]);
|
||||
sp[tempid].spellgroup=atoi(row[207]);
|
||||
sp[tempid].rank = atoi(row[208]);
|
||||
|
||||
@ -108,16 +108,17 @@ enum SkillUseTypes
|
||||
/*13869*/ SkillBerserking,
|
||||
/*13902*/ SkillTaunt,
|
||||
/*05837*/ SkillFrenzy, // This appears to be the only listed one not grouped with the others
|
||||
/*00000*/ _EmuSkillCount // move to last position of active enumeration labels
|
||||
|
||||
// SoF+ specific skills
|
||||
// /*03670*/ SkillRemoveTraps,
|
||||
// /*13049*/ SkillTripleAttack,
|
||||
/*03670*/ SkillRemoveTraps,
|
||||
/*13049*/ SkillTripleAttack,
|
||||
|
||||
// RoF2+ specific skills
|
||||
// /*00789*/ Skill2HPiercing,
|
||||
// /*01216*/ SkillNone, // This needs to move down as new skills are added
|
||||
|
||||
/*00000*/ _EmuSkillCount // move to last position of active enumeration labels
|
||||
|
||||
// Skill Counts
|
||||
// /*-----*/ _SkillCount_62 = 75, // use for Ti and earlier max skill checks
|
||||
// /*-----*/ _SkillCount_SoF = 77, // use for SoF thru RoF1 max skill checks
|
||||
@ -170,7 +171,7 @@ enum SkillUseTypes
|
||||
};
|
||||
|
||||
// temporary until it can be sorted out...
|
||||
#define HIGHEST_SKILL SkillFrenzy
|
||||
#define HIGHEST_SKILL SkillTripleAttack
|
||||
// Spell Effects use this value to determine if an effect applies to all skills.
|
||||
#define ALL_SKILLS -1
|
||||
|
||||
|
||||
@ -447,7 +447,7 @@ bool IsTGBCompatibleSpell(uint16 spell_id)
|
||||
|
||||
bool IsBardSong(uint16 spell_id)
|
||||
{
|
||||
if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 127 && !spells[spell_id].IsDisciplineBuff)
|
||||
if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 255 && !spells[spell_id].IsDisciplineBuff)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@ -381,47 +381,47 @@ typedef enum {
|
||||
#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_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_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_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_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_FreePet 236 // not used
|
||||
#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_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_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_CharmBreakChance 243 // implemented - Total Domination
|
||||
#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_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_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_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_Blank 254 // implemented
|
||||
//#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_PetDiscipline 257 // not implemented as bonus - /pet hold
|
||||
#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_PetDiscipline 257 // not implemented as bonus - /pet hold
|
||||
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
|
||||
#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_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live)
|
||||
#define SE_RaiseStatCap 262 // implemented
|
||||
//#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_TradeSkillMastery 263 // not implemented - lets you raise more than one tradeskill above master.
|
||||
#define SE_HastenedAASkill 264 // implemented
|
||||
#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_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_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
|
||||
@ -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_Flurry 279 // implemented
|
||||
#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_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk
|
||||
//#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_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_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap
|
||||
#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_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_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_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_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_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_ResistCorruption 370 // implemented
|
||||
#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_ApplyEffect 374 // implemented
|
||||
#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_FcTimerRefresh 389 // implemented - Refresh spell icons
|
||||
//#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_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.
|
||||
@ -579,7 +579,7 @@ typedef enum {
|
||||
#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_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_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.
|
||||
@ -735,8 +735,8 @@ struct SPDat_Spell_Struct
|
||||
/* 198- 199 */
|
||||
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones
|
||||
/* 201 */ int viral_range;
|
||||
/* 202 */
|
||||
/* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented)
|
||||
/* 202 */ int songcap; // individual song cap
|
||||
/* 203 */
|
||||
/* 204 */
|
||||
/* 205 */ bool no_block;
|
||||
/* 206 */
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9083
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9086
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
#ifndef WIN32
|
||||
|
||||
@ -102,8 +102,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Launcher, "Starting main loop...");
|
||||
|
||||
// zones["test"] = new ZoneLaunch(&world, "./zone", "dynamic_1");
|
||||
|
||||
ProcLauncher *launch = ProcLauncher::get();
|
||||
RunLoops = true;
|
||||
while(RunLoops) {
|
||||
|
||||
@ -86,14 +86,13 @@ void WorldServer::Process() {
|
||||
}
|
||||
const LauncherZoneRequest *lzr = (const LauncherZoneRequest *) pack->pBuffer;
|
||||
|
||||
|
||||
switch(ZoneRequestCommands(lzr->command)) {
|
||||
case ZR_Start: {
|
||||
if(m_zones.find(lzr->short_name) != m_zones.end()) {
|
||||
Log.Out(Logs::Detail, Logs::Launcher, "World told us to start zone %s, but it is already running.", lzr->short_name);
|
||||
} else {
|
||||
Log.Out(Logs::Detail, Logs::Launcher, "World told us to start zone %s.", lzr->short_name);
|
||||
ZoneLaunch *l = new ZoneLaunch(this, m_name, lzr->short_name, m_config);
|
||||
ZoneLaunch *l = new ZoneLaunch(this, m_name, lzr->short_name, lzr->port, m_config);
|
||||
m_zones[lzr->short_name] = l;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -34,10 +34,11 @@ void ZoneLaunch::InitStartTimer() {
|
||||
}
|
||||
|
||||
ZoneLaunch::ZoneLaunch(WorldServer *world, const char *launcher_name,
|
||||
const char *zone_name, const EQEmuConfig *config)
|
||||
const char *zone_name, uint16 port, const EQEmuConfig *config)
|
||||
: m_state(StateStartPending),
|
||||
m_world(world),
|
||||
m_zone(zone_name),
|
||||
m_port(port),
|
||||
m_launcherName(launcher_name),
|
||||
m_config(config),
|
||||
m_timer(config->RestartWait),
|
||||
@ -61,10 +62,14 @@ void ZoneLaunch::SendStatus() const {
|
||||
void ZoneLaunch::Start() {
|
||||
ProcLauncher::Spec *spec = new ProcLauncher::Spec();
|
||||
spec->program = m_config->ZoneExe;
|
||||
// if(m_zone.substr(0,7) == "dynamic")
|
||||
// spec->args.push_back(".");
|
||||
// else
|
||||
|
||||
if(m_port) {
|
||||
std::string arg = m_zone + std::string(":") + std::to_string(m_port);
|
||||
spec->args.push_back(arg);
|
||||
} else {
|
||||
spec->args.push_back(m_zone);
|
||||
}
|
||||
|
||||
spec->args.push_back(m_launcherName);
|
||||
spec->handler = this;
|
||||
spec->logFile = m_config->LogPrefix + m_zone + m_config->LogSuffix;
|
||||
|
||||
@ -28,7 +28,7 @@ class EQEmuConfig;
|
||||
class ZoneLaunch : protected ProcLauncher::EventHandler {
|
||||
public:
|
||||
ZoneLaunch(WorldServer *world, const char *launcher_name,
|
||||
const char *zone_name, const EQEmuConfig *config);
|
||||
const char *zone_name, uint16 port, const EQEmuConfig *config);
|
||||
virtual ~ZoneLaunch();
|
||||
|
||||
void Stop(bool graceful = true);
|
||||
@ -63,6 +63,7 @@ protected:
|
||||
const std::string m_zone;
|
||||
const char *const m_launcherName;
|
||||
const EQEmuConfig *const m_config;
|
||||
const uint16 m_port;
|
||||
|
||||
Timer m_timer;
|
||||
ProcLauncher::ProcRef m_ref;
|
||||
|
||||
@ -353,6 +353,7 @@ OP_OpenContainer=0x0000
|
||||
OP_Marquee=0x502e
|
||||
OP_ItemRecastDelay=0x15a9
|
||||
#OP_OpenInventory=0x0000 # Likely does not exist in RoF -U
|
||||
OP_ResetAA=0x1669
|
||||
|
||||
# Expeditions
|
||||
OP_DzAddPlayer=0x4701
|
||||
|
||||
@ -337,6 +337,9 @@
|
||||
9081|2015_05_23_dbstr_us.sql|SHOW TABLES LIKE 'db_str'|empty|
|
||||
9082|2015_05_25_npc_types_texture_fields.sql|SHOW COLUMNS FROM `npc_types` LIKE 'armtexture'|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|
|
||||
9085|2015_07_01_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:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
/* This rescales the old peq runspeeds which were about 80 percent too high to new values */
|
||||
/* This section should only ever be run once */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.050 WHERE (npc_types.runspeed > 0 and npc_types.runspeed < 1.2);
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.325 WHERE (npc_types.runspeed > 1.19 and npc_types.runspeed < 1.75 and race != 73 and race != 72);
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.runspeed > 1.69 and npc_types.runspeed < 2.2);
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE (npc_types.runspeed > 2.19 and npc_types.runspeed < 3);
|
||||
UPDATE npc_types SET npc_types.runspeed = (npc_types.runspeed * 0.8) WHERE (npc_types.runspeed > 2.99 and npc_types.runspeed < 20);
|
||||
@ -0,0 +1,61 @@
|
||||
/* some specific by name */
|
||||
UPDATE npc_types SET npc_types.runspeed = 3.175 WHERE npc_types.name = 'a_shadowed_man';
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.name = 'aviak_egret';
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.name = 'froglok_hunter';
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.name = 'froglok_forager';
|
||||
/* rhinos */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 135;
|
||||
/* centaurs */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 16;
|
||||
/* griffins */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 47;
|
||||
/* wolves - use size, to not change cubs*/
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.race = 42 and npc_types.size > 5);
|
||||
/* sarnaks */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.325 WHERE npc_types.race = 131;
|
||||
/* sabertooth tigers - use size, to not change cubs*/
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.race = 119 and npc_types.size > 6);
|
||||
/* lions */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.race = 50 and npc_types.size > 7);
|
||||
/* panthers/pumas */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.race = 76;
|
||||
/* beetles */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.05 WHERE npc_types.race = 22;
|
||||
/*leeches*/
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.05 WHERE npc_types.race = 104;
|
||||
/*a_brontotherium*/
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.race = 169;
|
||||
/* raptors */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 163;
|
||||
/* vicious plants */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.race = 162;
|
||||
/* western wastes, drakes, cragwyrms and wyvern */
|
||||
UPDATE npc_types
|
||||
JOIN spawnentry ON npc_types.id = spawnentry.npcID
|
||||
JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID
|
||||
SET npc_types.runspeed = 1.575
|
||||
WHERE ((npc_types.race = 89 OR npc_types.race = 157 OR npc_types.race = 158) AND spawn2.zone = 'westwastes');
|
||||
/* velium hounds/wolves */
|
||||
UPDATE npc_types
|
||||
JOIN spawnentry ON npc_types.id = spawnentry.npcID
|
||||
JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID
|
||||
SET npc_types.runspeed = 1.850
|
||||
WHERE (npc_types.race = 42 AND spawn2.zone = 'westwastes');
|
||||
/* Overthere Specials, goons, etc. */
|
||||
UPDATE npc_types
|
||||
JOIN spawnentry ON npc_types.id = spawnentry.npcID
|
||||
JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID
|
||||
SET npc_types.runspeed = 1.850
|
||||
WHERE ((npc_types.race = 77 or npc_types.race = 147) AND spawn2.zone = 'overthere');
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.name = 'Captain_Rottgrime';
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.name = 'an_undead_marine';
|
||||
/* Pet Speeds. */
|
||||
UPDATE npc_types
|
||||
JOIN pets ON npc_types.id = pets.npcID
|
||||
SET npc_types.runspeed = 1.575;
|
||||
/* raptors in tim are slower than other raptors in kunark */
|
||||
UPDATE npc_types
|
||||
JOIN spawnentry ON npc_types.id = spawnentry.npcID
|
||||
JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID
|
||||
SET npc_types.runspeed = 1.325
|
||||
WHERE ( npc_types.race = 163 AND spawn2.zone = 'timorous' );
|
||||
1
utils/sql/git/optional/2015_07_05_LiveCombatRounds.sql
Normal file
1
utils/sql/git/optional/2015_07_05_LiveCombatRounds.sql
Normal file
@ -0,0 +1 @@
|
||||
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:UseLiveCombatRounds', 'true', 'If true use live NPC combat rules, false will use old rules.');
|
||||
27
utils/sql/git/optional/2015_07_06_TripleAttack.sql
Normal file
27
utils/sql/git/optional/2015_07_06_TripleAttack.sql
Normal file
@ -0,0 +1,27 @@
|
||||
DELIMITER $$
|
||||
DROP PROCEDURE IF EXISTS GrantTripleAttack$$
|
||||
CREATE PROCEDURE GrantTripleAttack()
|
||||
BEGIN
|
||||
DECLARE finished INT;
|
||||
DECLARE char_id INT;
|
||||
DECLARE skill_max INT;
|
||||
DECLARE cur CURSOR FOR SELECT character_data.id, skill_caps.cap FROM `character_data` LEFT JOIN `skill_caps` ON character_data.`level` = skill_caps.`level` AND character_data.class = skill_caps.class AND skill_caps.skillID = 76;
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
|
||||
|
||||
OPEN cur;
|
||||
|
||||
SET finished = 0;
|
||||
REPEAT
|
||||
FETCH cur INTO char_id, skill_max;
|
||||
|
||||
IF skill_max IS NOT NULL AND skill_max > 0 THEN
|
||||
REPLACE INTO `character_skills` (`id`, `skill_id`, `value`) VALUES(char_id, 76, skill_max);
|
||||
END IF;
|
||||
UNTIL finished END REPEAT;
|
||||
|
||||
CLOSE cur;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CALL GrantTripleAttack();
|
||||
DROP PROCEDURE GrantTripleAttack;
|
||||
@ -0,0 +1,7 @@
|
||||
/* This rescales the old peq runspeeds which were about 80 percent too high to new values */
|
||||
/* This section should only ever be run once */
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.050 WHERE (npc_types.runspeed > 0 and npc_types.runspeed < 1.2);
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.325 WHERE (npc_types.runspeed > 1.19 and npc_types.runspeed < 1.75 and race != 73 and race != 72);
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.runspeed > 1.69 and npc_types.runspeed < 2.2);
|
||||
UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE (npc_types.runspeed > 2.19 and npc_types.runspeed < 3);
|
||||
UPDATE npc_types SET npc_types.runspeed = 3 WHERE npc_types.runspeed > 3;
|
||||
1
utils/sql/git/required/2015_07_01_Marquee_Rule.sql
Normal file
1
utils/sql/git/required/2015_07_01_Marquee_Rule.sql
Normal file
@ -0,0 +1 @@
|
||||
INSERT INTO `rule_values` (`rule_name`, `rule_value`, `notes`) VALUES ('Character:MarqueeHPUpdates', 'false', 'Will show Health % in center of screen < 100%');
|
||||
20679
utils/sql/git/required/2015_07_02_aa_rework.sql
Normal file
20679
utils/sql/git/required/2015_07_02_aa_rework.sql
Normal file
File diff suppressed because it is too large
Load Diff
@ -152,7 +152,13 @@ void Client::SendEnterWorld(std::string name)
|
||||
void Client::SendExpansionInfo() {
|
||||
auto outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct));
|
||||
ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer;
|
||||
if(RuleB(World, UseClientBasedExpansionSettings)) {
|
||||
eis->Expansions = ExpansionFromClientVersion(eqs->GetClientVersion());
|
||||
//eis->Expansions = ExpansionFromClientVersion(this->GetCLE.
|
||||
} else {
|
||||
eis->Expansions = (RuleI(World, ExpansionSettings));
|
||||
}
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ bool LauncherLink::Process() {
|
||||
end = m_states.end();
|
||||
for(; cur != end; ++cur) {
|
||||
if(!cur->second.up) {
|
||||
StartZone(cur->first.c_str());
|
||||
StartZone(cur->first.c_str(), cur->second.port);
|
||||
}
|
||||
}
|
||||
m_bootTimer.Disable();
|
||||
@ -184,14 +184,6 @@ bool LauncherLink::Process() {
|
||||
|
||||
bool LauncherLink::ContainsZone(const char *short_name) const {
|
||||
return(m_states.find(short_name) != m_states.end());
|
||||
|
||||
/*
|
||||
* std::map<std::string, bool>::const_iterator cur, end;
|
||||
cur = m_states.begin();
|
||||
end = m_states.end();
|
||||
for(; cur != end; cur++) {
|
||||
if(
|
||||
}*/
|
||||
}
|
||||
|
||||
void LauncherLink::BootZone(const char *short_name, uint16 port) {
|
||||
@ -202,15 +194,20 @@ void LauncherLink::BootZone(const char *short_name, uint16 port) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "%s: Loaded zone '%s' on port %d", m_name.c_str(), short_name, zs.port);
|
||||
m_states[short_name] = zs;
|
||||
|
||||
StartZone(short_name);
|
||||
StartZone(short_name, port);
|
||||
}
|
||||
|
||||
void LauncherLink::StartZone(const char *short_name) {
|
||||
StartZone(short_name, 0);
|
||||
}
|
||||
|
||||
void LauncherLink::StartZone(const char *short_name, uint16 port) {
|
||||
auto pack = new ServerPacket(ServerOP_LauncherZoneRequest, sizeof(LauncherZoneRequest));
|
||||
LauncherZoneRequest* s = (LauncherZoneRequest *) pack->pBuffer;
|
||||
|
||||
strn0cpy(s->short_name, short_name, 32);
|
||||
s->command = ZR_Start;
|
||||
s->port = port;
|
||||
|
||||
SendPacket(pack);
|
||||
delete pack;
|
||||
@ -222,6 +219,7 @@ void LauncherLink::RestartZone(const char *short_name) {
|
||||
|
||||
strn0cpy(s->short_name, short_name, 32);
|
||||
s->command = ZR_Restart;
|
||||
s->port = 0;
|
||||
|
||||
SendPacket(pack);
|
||||
delete pack;
|
||||
@ -233,6 +231,7 @@ void LauncherLink::StopZone(const char *short_name) {
|
||||
|
||||
strn0cpy(s->short_name, short_name, 32);
|
||||
s->command = ZR_Stop;
|
||||
s->port = 0;
|
||||
|
||||
SendPacket(pack);
|
||||
delete pack;
|
||||
@ -332,35 +331,3 @@ void LauncherLink::Shutdown() {
|
||||
SendPacket(pack);
|
||||
delete pack;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ public:
|
||||
void Shutdown();
|
||||
void BootZone(const char *short_name, uint16 port);
|
||||
void StartZone(const char *short_name);
|
||||
void StartZone(const char *short_name, uint16 port);
|
||||
void RestartZone(const char *short_name);
|
||||
void StopZone(const char *short_name);
|
||||
void BootDynamics(uint8 new_total);
|
||||
|
||||
@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
SET(zone_sources
|
||||
aa.cpp
|
||||
aa_ability.cpp
|
||||
aggro.cpp
|
||||
attack.cpp
|
||||
beacon.cpp
|
||||
@ -126,6 +127,7 @@ SET(zone_sources
|
||||
|
||||
SET(zone_headers
|
||||
aa.h
|
||||
aa_ability.h
|
||||
basic_functions.h
|
||||
beacon.h
|
||||
bot.h
|
||||
|
||||
2271
zone/aa.cpp
2271
zone/aa.cpp
File diff suppressed because it is too large
Load Diff
638
zone/aa.h
638
zone/aa.h
@ -1,27 +1,8 @@
|
||||
|
||||
#ifndef 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)
|
||||
|
||||
//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 {
|
||||
aaActionNone = 0,
|
||||
aaActionAETaunt = 1,
|
||||
@ -42,21 +23,6 @@ typedef enum {
|
||||
aaActionFadingMemories = 16
|
||||
} 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
|
||||
groupAAMarkNPC = 0,
|
||||
groupAANPCHealth,
|
||||
@ -133,571 +99,6 @@ static const uint8 LeadershipAACosts[_maxLeaderAA][MAX_LEADERSHIP_TIERS] = {
|
||||
{ 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
|
||||
aaNone =0,
|
||||
aaInnateStrength =2,//implemented as bonus
|
||||
@ -2109,21 +1510,6 @@ typedef enum { //AA IDs
|
||||
//follow the highest AA ID
|
||||
} 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
|
||||
struct AA_SwarmPet {
|
||||
uint8 count; //number to summon
|
||||
@ -2131,23 +1517,6 @@ struct AA_SwarmPet {
|
||||
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
|
||||
aaActionActivate = 0,
|
||||
aaActionSetEXP = 1,
|
||||
@ -2167,4 +1536,11 @@ public:
|
||||
uint32 owner_id;
|
||||
};
|
||||
|
||||
enum AATimers
|
||||
{
|
||||
aaTimerRampage,
|
||||
aaTimerWarcry,
|
||||
aaTimerMax
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
70
zone/aa_ability.cpp
Normal file
70
zone/aa_ability.cpp
Normal 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
61
zone/aa_ability.h
Normal 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
56
zone/aa_rank.h
Normal 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
38
zone/aa_rank_effects.h
Normal 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
|
||||
663
zone/attack.cpp
663
zone/attack.cpp
@ -341,7 +341,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
|
||||
return(tohit_roll <= chancetohit);
|
||||
}
|
||||
|
||||
bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
bool Mob::AvoidDamage(Mob *other, int32 &damage, int hand)
|
||||
{
|
||||
/* called when a mob is attacked, does the checks to see if it's a hit
|
||||
* and does other mitigation checks. 'this' is the mob being attacked.
|
||||
@ -353,22 +353,32 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
* -4 - dodge
|
||||
*
|
||||
*/
|
||||
float skill;
|
||||
float bonus;
|
||||
float RollTable[4] = {0,0,0,0};
|
||||
float roll;
|
||||
|
||||
/* Order according to current (SoF+?) dev quotes:
|
||||
* https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3261772
|
||||
* https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3268227
|
||||
* Riposte 50, hDEX, must have weapon/fists, doesn't work on archery/throwing
|
||||
* Block 25, hDEX, works on archery/throwing, behind block done here if back to attacker base1 is chance
|
||||
* Parry 45, hDEX, doesn't work on throwing/archery, must be facing target
|
||||
* Dodge 45, hAGI, works on archery/throwing, monks can dodge attacks from behind
|
||||
* Shield Block, rand base1
|
||||
* Staff Block, rand base1
|
||||
* regular strike through
|
||||
* avoiding the attack (CheckHitChance)
|
||||
* As soon as one succeeds, none of the rest are checked
|
||||
*
|
||||
* Formula (all int math)
|
||||
* (posted for parry, assume rest at the same)
|
||||
* Chance = (((SKILL + 100) + [((SKILL+100) * SPA(175).Base1) / 100]) / 45) + [(hDex / 25) - min([hDex / 25], hStrikethrough)].
|
||||
* hStrikethrough is a mob stat that was added to counter the bonuses of heroic stats
|
||||
* Number rolled against 100, if the chance is greater than 100 it happens 100% of time
|
||||
*
|
||||
* Things with 10k accuracy mods can be avoided with these skills qq
|
||||
*/
|
||||
Mob *attacker = other;
|
||||
Mob *defender = this;
|
||||
|
||||
//garunteed hit
|
||||
bool ghit = false;
|
||||
if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
||||
ghit = true;
|
||||
|
||||
bool InFront = false;
|
||||
|
||||
if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY()))
|
||||
InFront = true;
|
||||
bool InFront = attacker->InFrontMob(this, attacker->GetX(), attacker->GetY());
|
||||
|
||||
/*
|
||||
This special ability adds a negative modifer to the defenders riposte/block/parry/chance
|
||||
@ -384,7 +394,6 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
int counter_dodge = 0;
|
||||
|
||||
if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)) {
|
||||
|
||||
counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0);
|
||||
counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 1);
|
||||
counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2);
|
||||
@ -400,31 +409,37 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// riposte
|
||||
/////////////////////////////////////////////////////////
|
||||
float riposte_chance = 0.0f;
|
||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront)
|
||||
{
|
||||
riposte_chance = (100.0f + static_cast<float>(aabonuses.RiposteChance + spellbonuses.RiposteChance +
|
||||
itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f;
|
||||
skill = GetSkill(SkillRiposte);
|
||||
if (IsClient()) {
|
||||
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
|
||||
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance;
|
||||
// Need to check if we have something in MainHand to actually attack with (or fists)
|
||||
if (hand != MainRange && CanThisClassRiposte() && InFront && !ImmuneRipo) {
|
||||
if (IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
|
||||
// check auto discs ... I guess aa/items too :P
|
||||
if (spellbonuses.RiposteChance == 10000 || aabonuses.RiposteChance == 10000 || itembonuses.RiposteChance == 10000) {
|
||||
damage = -3;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
||||
bonus = 2.0 + skill/60.0 + (GetDEX()/200);
|
||||
bonus *= riposte_chance;
|
||||
bonus = mod_riposte_chance(bonus, attacker);
|
||||
RollTable[0] = bonus + (itembonuses.HeroicDEX / 25); // 25 heroic = 1%, applies to ripo, parry, block
|
||||
int chance = GetSkill(SkillRiposte) + 100;
|
||||
chance += (chance * (aabonuses.RiposteChance + spellbonuses.RiposteChance + itembonuses.RiposteChance)) / 100;
|
||||
chance /= 50;
|
||||
chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter
|
||||
if (counter_riposte || counter_all) {
|
||||
float counter = (counter_riposte + counter_all) / 100.0f;
|
||||
chance -= chance * counter;
|
||||
}
|
||||
// AA Slippery Attacks
|
||||
if (hand == MainSecondary) {
|
||||
int slip = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail;
|
||||
chance += chance * slip / 100;
|
||||
}
|
||||
if (chance > 0 && zone->random.Roll(chance)) { // could be <0 from offhand stuff
|
||||
damage = -3;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// block
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
bool bBlockFromRear = false;
|
||||
|
||||
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
||||
@ -435,101 +450,100 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
if (BlockBehindChance && zone->random.Roll(BlockBehindChance))
|
||||
bBlockFromRear = true;
|
||||
|
||||
float block_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) {
|
||||
block_chance = (100.0f + static_cast<float>(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance +
|
||||
itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f;
|
||||
skill = CastToClient()->GetSkill(SkillBlock);
|
||||
if (IsClient()) {
|
||||
if (CanThisClassBlock() && (InFront || bBlockFromRear)) {
|
||||
if (IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10);
|
||||
// check auto discs ... I guess aa/items too :P
|
||||
if (spellbonuses.IncreaseBlockChance == 10000 || aabonuses.IncreaseBlockChance == 10000 ||
|
||||
itembonuses.IncreaseBlockChance == 10000) {
|
||||
damage = -1;
|
||||
return true;
|
||||
}
|
||||
int chance = GetSkill(SkillBlock) + 100;
|
||||
chance += (chance * (aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance + itembonuses.IncreaseBlockChance)) / 100;
|
||||
chance /= 25;
|
||||
chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter
|
||||
if (counter_block || counter_all) {
|
||||
float counter = (counter_block + counter_all) / 100.0f;
|
||||
chance -= chance * counter;
|
||||
}
|
||||
if (zone->random.Roll(chance)) {
|
||||
damage = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
||||
bonus = 2.0 + skill/35.0 + (GetDEX()/200);
|
||||
bonus = mod_block_chance(bonus, attacker);
|
||||
RollTable[1] = RollTable[0] + (bonus * block_chance);
|
||||
// parry
|
||||
if (CanThisClassParry() && InFront && hand != MainRange) {
|
||||
if (IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
||||
// check auto discs ... I guess aa/items too :P
|
||||
if (spellbonuses.ParryChance == 10000 || aabonuses.ParryChance == 10000 || itembonuses.ParryChance == 10000) {
|
||||
damage = -2;
|
||||
return true;
|
||||
}
|
||||
int chance = GetSkill(SkillParry) + 100;
|
||||
chance += (chance * (aabonuses.ParryChance + spellbonuses.ParryChance + itembonuses.ParryChance)) / 100;
|
||||
chance /= 45;
|
||||
chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter
|
||||
if (counter_parry || counter_all) {
|
||||
float counter = (counter_parry + counter_all) / 100.0f;
|
||||
chance -= chance * counter;
|
||||
}
|
||||
if (zone->random.Roll(chance)) {
|
||||
damage = -2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else{
|
||||
RollTable[1] = RollTable[0];
|
||||
|
||||
// dodge
|
||||
if (CanThisClassDodge() && (InFront || GetClass() == MONK) ) {
|
||||
if (IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
||||
// check auto discs ... I guess aa/items too :P
|
||||
if (spellbonuses.DodgeChance == 10000 || aabonuses.DodgeChance == 10000 || itembonuses.DodgeChance == 10000) {
|
||||
damage = -4;
|
||||
return true;
|
||||
}
|
||||
int chance = GetSkill(SkillDodge) + 100;
|
||||
chance += (chance * (aabonuses.DodgeChance + spellbonuses.DodgeChance + itembonuses.DodgeChance)) / 100;
|
||||
chance /= 45;
|
||||
chance += itembonuses.HeroicAGI / 25; // live has "heroic strickthrough" here to counter
|
||||
if (counter_dodge || counter_all) {
|
||||
float counter = (counter_dodge + counter_all) / 100.0f;
|
||||
chance -= chance * counter;
|
||||
}
|
||||
if (zone->random.Roll(chance)) {
|
||||
damage = -4;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Try Shield Block OR TwoHandBluntBlockCheck
|
||||
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear))
|
||||
RollTable[1] += static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all);
|
||||
|
||||
else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear))
|
||||
RollTable[1] += static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all);
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// parry
|
||||
//////////////////////////////////////////////////////
|
||||
float parry_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassParry() && InFront){
|
||||
parry_chance = (100.0f + static_cast<float>(aabonuses.ParryChance + itembonuses.ParryChance +
|
||||
itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f;
|
||||
skill = CastToClient()->GetSkill(SkillParry);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
||||
if (HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear)) {
|
||||
int chance = aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock;
|
||||
if (counter_block || counter_all) {
|
||||
float counter = (counter_block + counter_all) / 100.0f;
|
||||
chance -= chance * counter;
|
||||
}
|
||||
|
||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
||||
bonus = 2.0 + skill/60.0 + (GetDEX()/200);
|
||||
bonus *= parry_chance;
|
||||
bonus = mod_parry_chance(bonus, attacker);
|
||||
RollTable[2] = RollTable[1] + bonus;
|
||||
}
|
||||
}
|
||||
else{
|
||||
RollTable[2] = RollTable[1];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// dodge
|
||||
////////////////////////////////////////////////////////
|
||||
float dodge_chance = 0.0f;
|
||||
if (damage > 0 && CanThisClassDodge() && InFront){
|
||||
|
||||
dodge_chance = (100.0f + static_cast<float>(aabonuses.DodgeChance + spellbonuses.DodgeChance +
|
||||
itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f;
|
||||
|
||||
skill = CastToClient()->GetSkill(SkillDodge);
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
||||
}
|
||||
|
||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
||||
bonus = 2.0 + skill/60.0 + (GetAGI()/200);
|
||||
bonus *= dodge_chance;
|
||||
//DCBOOMKAR
|
||||
bonus = mod_dodge_chance(bonus, attacker);
|
||||
RollTable[3] = RollTable[2] + bonus - (itembonuses.HeroicDEX / 25) + (itembonuses.HeroicAGI / 25);
|
||||
}
|
||||
}
|
||||
else{
|
||||
RollTable[3] = RollTable[2];
|
||||
}
|
||||
|
||||
if(damage > 0){
|
||||
roll = zone->random.Real(0,100);
|
||||
if(roll <= RollTable[0]){
|
||||
damage = -3;
|
||||
}
|
||||
else if(roll <= RollTable[1]){
|
||||
if (zone->random.Roll(chance)) {
|
||||
damage = -1;
|
||||
}
|
||||
else if(roll <= RollTable[2]){
|
||||
damage = -2;
|
||||
}
|
||||
else if(roll <= RollTable[3]){
|
||||
damage = -4;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all avoidances: %d", damage);
|
||||
|
||||
if (damage < 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear)) {
|
||||
int chance = aabonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock;
|
||||
if (counter_block || counter_all) {
|
||||
float counter = (counter_block + counter_all) / 100.0f;
|
||||
chance -= chance * counter;
|
||||
}
|
||||
if (zone->random.Roll(chance)) {
|
||||
damage = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1286,6 +1300,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
}
|
||||
}
|
||||
|
||||
// this effect is actually a min cap that happens after the final damage is calculated
|
||||
min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100;
|
||||
|
||||
if(max_hit < min_hit)
|
||||
@ -1312,66 +1327,52 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
}
|
||||
|
||||
//check to see if we hit..
|
||||
if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0.");
|
||||
damage = 0;
|
||||
} else { //we hit, try to avoid it
|
||||
other->AvoidDamage(this, damage);
|
||||
other->MeleeMitigation(this, damage, min_hit, opts);
|
||||
if(damage > 0)
|
||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage);
|
||||
}
|
||||
|
||||
//riposte
|
||||
bool slippery_attack = false; // Part of hack to allow riposte to become a miss, but still allow a Strikethrough chance (like on Live)
|
||||
if (damage == -3) {
|
||||
if (bRiposte) return false;
|
||||
else {
|
||||
if (Hand == MainSecondary) {// Do we even have it & was attack with mainhand? If not, don't bother with other calculations
|
||||
//Live AA - SlipperyAttacks
|
||||
//This spell effect most likely directly modifies the actual riposte chance when using offhand attack.
|
||||
int32 OffhandRiposteFail = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail;
|
||||
OffhandRiposteFail *= -1; //Live uses a negative value for this.
|
||||
|
||||
if (OffhandRiposteFail &&
|
||||
(OffhandRiposteFail > 99 || zone->random.Roll(OffhandRiposteFail))) {
|
||||
damage = 0; // Counts as a miss
|
||||
slippery_attack = true;
|
||||
} else
|
||||
DoRiposte(other);
|
||||
if (IsDead()) return false;
|
||||
}
|
||||
else
|
||||
DoRiposte(other);
|
||||
if (IsDead()) return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (((damage < 0) || slippery_attack) && !bRiposte && !IsStrikethrough) { // Hack to still allow Strikethrough chance w/ Slippery Attacks AA
|
||||
int32 bonusStrikeThrough = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
||||
|
||||
if(bonusStrikeThrough && zone->random.Roll(bonusStrikeThrough)) {
|
||||
if (other->AvoidDamage(this, damage, Hand)) {
|
||||
if (!bRiposte && !IsStrikethrough) {
|
||||
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
||||
if(strike_through && zone->random.Roll(strike_through)) {
|
||||
Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses!
|
||||
Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit
|
||||
return false;
|
||||
}
|
||||
// I'm pretty sure you can riposte a riposte
|
||||
if (damage == -3 && !bRiposte) {
|
||||
DoRiposte(other);
|
||||
if (IsDead())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Avoided damage with code %d", damage);
|
||||
} else {
|
||||
if (other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
||||
other->MeleeMitigation(this, damage, min_hit, opts);
|
||||
if (damage > 0)
|
||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage);
|
||||
} else {
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0.");
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
damage = -5;
|
||||
}
|
||||
|
||||
// Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same.
|
||||
// If we are this far, this means we are atleast making a swing.
|
||||
|
||||
if (!bRiposte) // Ripostes never generate any aggro.
|
||||
other->AddToHateList(this, hate);
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
////// 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);
|
||||
|
||||
if (IsDead()) return false;
|
||||
@ -1905,21 +1906,18 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
hit_chance_bonus += opts->hit_chance;
|
||||
}
|
||||
|
||||
if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
||||
damage = 0; //miss
|
||||
} else { //hit, check for damage avoidance
|
||||
other->AvoidDamage(this, damage);
|
||||
if (other->AvoidDamage(this, damage, Hand)) {
|
||||
if (!bRiposte && damage == -3)
|
||||
DoRiposte(other);
|
||||
} else {
|
||||
if (other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
||||
other->MeleeMitigation(this, damage, min_dmg+eleBane, opts);
|
||||
if(damage > 0) {
|
||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||
} else {
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Generating hate %d towards %s", hate, GetName());
|
||||
// now add done damage to the hate list
|
||||
if(damage > 0)
|
||||
other->AddToHateList(this, hate);
|
||||
else
|
||||
other->AddToHateList(this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage against %s: %d", other->GetName(), damage);
|
||||
@ -1932,12 +1930,6 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
else
|
||||
damage = -5;
|
||||
|
||||
//cant riposte a riposte
|
||||
if (bRiposte && damage == -3) {
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Riposte of riposte canceled.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(GetHP() > 0 && !other->HasDied()) {
|
||||
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, false); // Not avoidable client already had thier chance to Avoid
|
||||
} else
|
||||
@ -1967,11 +1959,6 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
if(GetHP() > 0 && !other->HasDied())
|
||||
TriggerDefensiveProcs(nullptr, other, Hand, damage);
|
||||
|
||||
// now check ripostes
|
||||
if (damage == -3) { // riposting
|
||||
DoRiposte(other);
|
||||
}
|
||||
|
||||
if (damage > 0)
|
||||
return true;
|
||||
|
||||
@ -3419,41 +3406,39 @@ bool Mob::HasRangedProcs() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::CheckDoubleAttack(bool tripleAttack) {
|
||||
|
||||
bool Client::CheckDoubleAttack()
|
||||
{
|
||||
int chance = 0;
|
||||
int skill = GetSkill(SkillDoubleAttack);
|
||||
//Check for bonuses that give you a double attack chance regardless of skill (ie Bestial Frenzy/Harmonious Attack AA)
|
||||
uint32 bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack;
|
||||
|
||||
if(!HasSkill(SkillDoubleAttack) && !bonusGiveDA)
|
||||
int bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack;
|
||||
if (skill > 0)
|
||||
chance = skill + GetLevel();
|
||||
else if (!bonusGiveDA)
|
||||
return false;
|
||||
|
||||
float chance = 0.0f;
|
||||
if (bonusGiveDA)
|
||||
chance += bonusGiveDA / 100.0f * 500; // convert to skill value
|
||||
int per_inc = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance;
|
||||
if (per_inc)
|
||||
chance += chance * per_inc / 100;
|
||||
|
||||
uint16 skill = GetSkill(SkillDoubleAttack);
|
||||
|
||||
int32 bonusDA = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance;
|
||||
|
||||
//Use skill calculations otherwise, if you only have AA applied GiveDoubleAttack chance then use that value as the base.
|
||||
if (skill)
|
||||
chance = (float(skill+GetLevel()) * (float(100.0f+bonusDA+bonusGiveDA) /100.0f)) /500.0f;
|
||||
else
|
||||
chance = (float(bonusGiveDA) * (float(100.0f+bonusDA)/100.0f) ) /100.0f;
|
||||
|
||||
//Live now uses a static Triple Attack skill (lv 46 = 2% lv 60 = 20%) - We do not have this skill on EMU ATM.
|
||||
//A reasonable forumla would then be TA = 20% * chance
|
||||
//AA's can also give triple attack skill over cap. (ie Burst of Power) NOTE: Skill ID in spell data is 76 (Triple Attack)
|
||||
//Kayen: Need to decide if we can implement triple attack skill before working in over the cap effect.
|
||||
if(tripleAttack) {
|
||||
// Only some Double Attack classes get Triple Attack [This is already checked in client_processes.cpp]
|
||||
int32 triple_bonus = spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance;
|
||||
chance *= 0.2f; //Baseline chance is 20% of your double attack chance.
|
||||
chance *= float(100.0f+triple_bonus)/100.0f; //Apply modifiers.
|
||||
return zone->random.Int(1, 500) <= chance;
|
||||
}
|
||||
|
||||
if(zone->random.Roll(chance))
|
||||
return true;
|
||||
|
||||
// Admittedly these parses were short, but this check worked for 3 toons across multiple levels
|
||||
// with varying triple attack skill (1-3% error at least)
|
||||
bool Client::CheckTripleAttack()
|
||||
{
|
||||
int chance = GetSkill(SkillTripleAttack);
|
||||
if (chance < 1)
|
||||
return false;
|
||||
|
||||
int per_inc = aabonuses.TripleAttackChance + spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance;
|
||||
if (per_inc)
|
||||
chance += chance * per_inc / 100;
|
||||
|
||||
return zone->random.Int(1, 1000) <= chance;
|
||||
}
|
||||
|
||||
bool Client::CheckDoubleRangedAttack() {
|
||||
@ -3465,6 +3450,21 @@ bool Client::CheckDoubleRangedAttack() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mob::CheckDoubleAttack()
|
||||
{
|
||||
// Not 100% certain pets follow this or if it's just from pets not always
|
||||
// having the same skills as most mobs
|
||||
int chance = GetSkill(SkillDoubleAttack);
|
||||
if (GetLevel() > 35)
|
||||
chance += GetLevel();
|
||||
|
||||
int per_inc = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance;
|
||||
if (per_inc)
|
||||
chance += chance * per_inc / 100;
|
||||
|
||||
return zone->random.Int(1, 500) <= chance;
|
||||
}
|
||||
|
||||
void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, const SkillUseTypes skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic) {
|
||||
// This method is called with skill_used=ABJURE for Damage Shield damage.
|
||||
bool FromDamageShield = (skill_used == SkillAbjuration);
|
||||
@ -3512,14 +3512,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
if(damage > 0) {
|
||||
//if there is some damage being done and theres an attacker involved
|
||||
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_id != SPELL_UNKNOWN && IsLifetapSpell( spell_id )) {
|
||||
int healed = damage;
|
||||
@ -3583,6 +3575,9 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
|
||||
SetHP(GetHP() - damage);
|
||||
|
||||
if (IsClient())
|
||||
this->CastToClient()->SendHPUpdateMarquee();
|
||||
|
||||
if(HasDied()) {
|
||||
bool IsSaved = false;
|
||||
|
||||
@ -3693,11 +3688,11 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
|
||||
//send an HP update if we are hurt
|
||||
if(GetHP() < GetMaxHP())
|
||||
SendHPUpdate(!iBuffTic); // the OP_Damage actually updates the client in these cases, so we skill them
|
||||
SendHPUpdate(!iBuffTic); // the OP_Damage actually updates the client in these cases, so we skip the HP update for them
|
||||
} //end `if damage was done`
|
||||
|
||||
//send damage packet...
|
||||
if(!iBuffTic) { //buff ticks do not send damage, instead they just call SendHPUpdate(), which is done below
|
||||
if(!iBuffTic) { //buff ticks do not send damage, instead they just call SendHPUpdate(), which is done above
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
|
||||
CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer;
|
||||
a->target = GetID();
|
||||
@ -4413,41 +4408,54 @@ bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse)
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mob::DoRiposte(Mob* defender) {
|
||||
void Mob::DoRiposte(Mob *defender)
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Preforming a riposte");
|
||||
|
||||
if (!defender)
|
||||
return;
|
||||
|
||||
defender->Attack(this, MainPrimary, true);
|
||||
if (HasDied()) return;
|
||||
if (HasDied())
|
||||
return;
|
||||
|
||||
int32 DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[0] +
|
||||
defender->spellbonuses.GiveDoubleRiposte[0] +
|
||||
defender->itembonuses.GiveDoubleRiposte[0];
|
||||
|
||||
DoubleRipChance = defender->aabonuses.DoubleRiposte +
|
||||
defender->spellbonuses.DoubleRiposte +
|
||||
// this effect isn't used on live? See no AAs or spells
|
||||
int32 DoubleRipChance = defender->aabonuses.DoubleRiposte + defender->spellbonuses.DoubleRiposte +
|
||||
defender->itembonuses.DoubleRiposte;
|
||||
|
||||
if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) {
|
||||
Log.Out(Logs::Detail, Logs::Combat,
|
||||
"Preforming a double riposted from SE_DoubleRiposte (%d percent chance)", DoubleRipChance);
|
||||
defender->Attack(this, MainPrimary, true);
|
||||
if (HasDied())
|
||||
return;
|
||||
}
|
||||
|
||||
DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[0] + defender->spellbonuses.GiveDoubleRiposte[0] +
|
||||
defender->itembonuses.GiveDoubleRiposte[0];
|
||||
|
||||
// Live AA - Double Riposte
|
||||
if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) {
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Preforming a double riposed (%d percent chance)", 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;
|
||||
if (HasDied())
|
||||
return;
|
||||
}
|
||||
|
||||
//Double Riposte effect, allows for a chance to do RIPOSTE with a skill specfic special attack (ie Return Kick).
|
||||
// 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];
|
||||
|
||||
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)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -4640,7 +4648,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
if (IsClient() && aabonuses.LimitToSkill[skill]){
|
||||
|
||||
CanProc = true;
|
||||
uint32 effect = 0;
|
||||
uint32 effect_id = 0;
|
||||
int32 base1 = 0;
|
||||
int32 base2 = 0;
|
||||
uint32 slot = 0;
|
||||
@ -4659,22 +4667,26 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
proc_spell_id = 0;
|
||||
ProcMod = 0;
|
||||
|
||||
std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aaid);
|
||||
if(find_iter == aa_effects.end())
|
||||
break;
|
||||
for(auto &rank_info : aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_info.first, rank_info.second.first);
|
||||
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) {
|
||||
effect = iter->second.skill_id;
|
||||
base1 = iter->second.base1;
|
||||
base2 = iter->second.base2;
|
||||
slot = iter->second.slot;
|
||||
if(!ability) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
ProcMod = static_cast<float>(base2);
|
||||
}
|
||||
|
||||
else if (effect == SE_LimitToSkill && base1 <= HIGHEST_SKILL) {
|
||||
else if(effect_id == SE_LimitToSkill && base1 <= HIGHEST_SKILL) {
|
||||
|
||||
if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) {
|
||||
float final_chance = chance * (ProcMod / 100.0f);
|
||||
@ -4695,6 +4707,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
|
||||
|
||||
@ -4906,7 +4919,6 @@ void Client::SetAttackTimer()
|
||||
attack_timer.SetAtTrigger(4000, true);
|
||||
|
||||
Timer *TimerToUse = nullptr;
|
||||
const Item_Struct *PrimaryWeapon = nullptr;
|
||||
|
||||
for (int i = MainRange; i <= MainSecondary; i++) {
|
||||
//pick a timer
|
||||
@ -4928,19 +4940,8 @@ void Client::SetAttackTimer()
|
||||
|
||||
//special offhand stuff
|
||||
if (i == MainSecondary) {
|
||||
//if we have a 2H weapon in our main hand, no dual
|
||||
if (PrimaryWeapon != nullptr) {
|
||||
if (PrimaryWeapon->ItemClass == ItemClassCommon
|
||||
&& (PrimaryWeapon->ItemType == ItemType2HSlash
|
||||
|| PrimaryWeapon->ItemType == ItemType2HBlunt
|
||||
|| PrimaryWeapon->ItemType == ItemType2HPiercing)) {
|
||||
attack_dw_timer.Disable();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//if we cant dual wield, skip it
|
||||
if (!CanThisClassDualWield()) {
|
||||
if (!CanThisClassDualWield() || HasTwoHanderEquipped()) {
|
||||
attack_dw_timer.Disable();
|
||||
continue;
|
||||
}
|
||||
@ -4989,9 +4990,6 @@ void Client::SetAttackTimer()
|
||||
if (quiver_haste > 0)
|
||||
speed *= quiver_haste;
|
||||
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
|
||||
|
||||
if (i == MainPrimary)
|
||||
PrimaryWeapon = ItemToUse;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5029,8 +5027,8 @@ void NPC::SetAttackTimer()
|
||||
|
||||
//special offhand stuff
|
||||
if (i == MainSecondary) {
|
||||
//NPCs get it for free at 13
|
||||
if(GetLevel() < 13) {
|
||||
// SPECATK_QUAD is uncheesable
|
||||
if(!CanThisClassDualWield() || (HasTwoHanderEquipped() && !GetSpecialAbility(SPECATK_QUAD))) {
|
||||
attack_dw_timer.Disable();
|
||||
continue;
|
||||
}
|
||||
@ -5039,3 +5037,140 @@ void NPC::SetAttackTimer()
|
||||
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);
|
||||
|
||||
bool candouble = CanThisClassDoubleAttack();
|
||||
// extra off hand non-sense, can only double with skill of 150 or above
|
||||
// or you have any amount of GiveDoubleAttack
|
||||
if (candouble && hand == MainSecondary)
|
||||
candouble = GetSkill(SkillDoubleAttack) > 149 || (aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0;
|
||||
|
||||
if (candouble) {
|
||||
CheckIncreaseSkill(SkillDoubleAttack, target, -10);
|
||||
if (CheckDoubleAttack()) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
// you can only triple from the main hand
|
||||
if (hand == MainPrimary && CanThisClassTripleAttack()) {
|
||||
CheckIncreaseSkill(SkillTripleAttack, target, -10);
|
||||
if (CheckTripleAttack())
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hand == MainPrimary) {
|
||||
// According to http://www.monkly-business.net/forums/showpost.php?p=312095&postcount=168 a dev told them flurry isn't dependant on triple attack
|
||||
// the parses kind of back that up and all of my parses seemed to be 4 or 5 attacks in the round which would work out to be
|
||||
// doubles or triples with 2 from flurries or triple with 1 or 2 flurries ... Going with the "dev quote" I guess like we've always had it
|
||||
auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance;
|
||||
if (flurrychance && zone->random.Roll(flurrychance)) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
Message_StringID(MT_NPCFlurry, YOU_FLURRY);
|
||||
}
|
||||
// I haven't parsed where this guy happens, but it's not part of the normal chain above so this is fine
|
||||
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance;
|
||||
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::CheckDualWield()
|
||||
{
|
||||
// Pets /might/ follow a slightly different progression
|
||||
// although it could all be from pets having different skills than most mobs
|
||||
int chance = GetSkill(SkillDualWield);
|
||||
if (GetLevel() > 35)
|
||||
chance += GetLevel();
|
||||
|
||||
chance += aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity;
|
||||
int per_inc = spellbonuses.DualWieldChance + aabonuses.DualWieldChance + itembonuses.DualWieldChance;
|
||||
if (per_inc)
|
||||
chance += chance * per_inc / 100;
|
||||
|
||||
return zone->random.Int(1, 375) <= chance;
|
||||
}
|
||||
|
||||
bool Client::CheckDualWield()
|
||||
{
|
||||
int chance = GetSkill(SkillDualWield) + GetLevel();
|
||||
|
||||
chance += aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity;
|
||||
int per_inc = spellbonuses.DualWieldChance + aabonuses.DualWieldChance + itembonuses.DualWieldChance;
|
||||
if (per_inc)
|
||||
chance += chance * per_inc / 100;
|
||||
|
||||
return zone->random.Int(1, 375) <= chance;
|
||||
}
|
||||
|
||||
void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (RuleB(Combat, UseLiveCombatRounds)) {
|
||||
// A "quad" on live really is just a successful dual wield where both double attack
|
||||
// The mobs that could triple lost the ability to when the triple attack skill was added in
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
if (CanThisClassDoubleAttack() && CheckDoubleAttack())
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
int16 n_atk = CastToNPC()->GetNumberOfAttacks();
|
||||
if (n_atk <= 1) {
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
} else {
|
||||
for (int i = 0; i < n_atk; ++i) {
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
}
|
||||
|
||||
// we use this random value in three comparisons with different
|
||||
// thresholds, and if its truely random, then this should work
|
||||
// out reasonably and will save us compute resources.
|
||||
int32 RandRoll = zone->random.Int(0, 99);
|
||||
if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD))
|
||||
// check double attack, this is NOT the same rules that clients use...
|
||||
&&
|
||||
RandRoll < (GetLevel() + NPCDualAttackModifier)) {
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
// lets see if we can do a triple attack with the main hand
|
||||
// pets are excluded from triple and quads...
|
||||
if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) && !IsPet() &&
|
||||
RandRoll < (GetLevel() + NPCTripleAttackModifier)) {
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
// now lets check the quad attack
|
||||
if (GetSpecialAbility(SPECATK_QUAD) && RandRoll < (GetLevel() + NPCQuadAttackModifier)) {
|
||||
Attack(target, MainPrimary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
// Mobs will only dual wield w/ the flag or have a secondary weapon
|
||||
// For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true
|
||||
if ((GetSpecialAbility(SPECATK_INNATE_DW) ||
|
||||
(RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SPECATK_QUAD))) ||
|
||||
GetEquipment(MaterialSecondary) != 0) {
|
||||
if (CheckDualWield()) {
|
||||
Attack(target, MainSecondary, false, false, false, opts);
|
||||
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack())
|
||||
Attack(target, MainSecondary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
393
zone/bonuses.cpp
393
zone/bonuses.cpp
@ -42,6 +42,7 @@
|
||||
void Mob::CalcBonuses()
|
||||
{
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
CalcAABonuses(&aabonuses);
|
||||
CalcMaxHP();
|
||||
CalcMaxMana();
|
||||
SetAttackTimer();
|
||||
@ -51,9 +52,7 @@ void Mob::CalcBonuses()
|
||||
|
||||
void NPC::CalcBonuses()
|
||||
{
|
||||
Mob::CalcBonuses();
|
||||
memset(&aabonuses, 0, sizeof(StatBonuses));
|
||||
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
if(RuleB(NPC, UseItemBonusesForNonPets)){
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
CalcItemBonuses(&itembonuses);
|
||||
@ -74,12 +73,8 @@ void Client::CalcBonuses()
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
CalcItemBonuses(&itembonuses);
|
||||
CalcEdibleBonuses(&itembonuses);
|
||||
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
|
||||
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());
|
||||
CalcAABonuses(&aabonuses);
|
||||
|
||||
ProcessItemCaps(); // caps that depend on spell/aa bonuses
|
||||
|
||||
@ -113,6 +108,9 @@ void Client::CalcBonuses()
|
||||
rooted = FindType(SE_Root);
|
||||
|
||||
XPRate = 100 + spellbonuses.XPRateMod;
|
||||
|
||||
if (GetMaxXTargets() != 5 + aabonuses.extra_xtargets)
|
||||
SetMaxXTargets(5 + aabonuses.extra_xtargets);
|
||||
}
|
||||
|
||||
int Client::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat)
|
||||
@ -143,6 +141,7 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
ClearItemFactionBonuses();
|
||||
SetShieldEquiped(false);
|
||||
SetTwoHandBluntEquiped(false);
|
||||
SetTwoHanderEquipped(false);
|
||||
|
||||
unsigned int i;
|
||||
//should not include 21 (SLOT_AMMO)
|
||||
@ -156,8 +155,11 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
const Item_Struct *item = inst->GetItem();
|
||||
if (i == MainSecondary && (item && item->ItemType == ItemTypeShield))
|
||||
SetShieldEquiped(true);
|
||||
else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt))
|
||||
else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt)) {
|
||||
SetTwoHandBluntEquiped(true);
|
||||
SetTwoHanderEquipped(true);
|
||||
} else if (i == MainPrimary && (item && (item->ItemType == ItemType2HSlash || item->ItemType == ItemType2HPiercing)))
|
||||
SetTwoHanderEquipped(true);
|
||||
}
|
||||
|
||||
//Power Source Slot
|
||||
@ -632,77 +634,70 @@ void Client::CalcEdibleBonuses(StatBonuses* newbon) {
|
||||
}
|
||||
}
|
||||
|
||||
void Client::CalcAABonuses(StatBonuses* newbon) {
|
||||
void Mob::CalcAABonuses(StatBonuses *newbon)
|
||||
{
|
||||
memset(newbon, 0, sizeof(StatBonuses)); // start fresh
|
||||
|
||||
int i;
|
||||
uint32 slots = 0;
|
||||
uint32 aa_AA = 0;
|
||||
uint32 aa_value = 0;
|
||||
if(this->aa) {
|
||||
for (i = 0; i < MAX_PP_AA_ARRAY; i++) { //iterate through all of the client's AAs
|
||||
if (this->aa[i]) { // make sure aa exists or we'll crash zone
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &aa : aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
|
||||
if(!ability) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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).
|
||||
//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
|
||||
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;
|
||||
|
||||
//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;
|
||||
for (const auto &e : rank.effects) {
|
||||
effect = e.effect_id;
|
||||
base1 = e.base1;
|
||||
base2 = e.base2;
|
||||
slot = e.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)
|
||||
continue;
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
if (focus)
|
||||
{
|
||||
if (focus) {
|
||||
newbon->FocusEffects[focus] = static_cast<uint8>(effect);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (effect)
|
||||
{
|
||||
switch (effect) {
|
||||
// Note: AA effects that use accuracy are skill limited, while spell effect is not.
|
||||
case SE_Accuracy:
|
||||
// Bad data or unsupported new skill
|
||||
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)
|
||||
@ -746,6 +741,9 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_CurrentMana:
|
||||
newbon->ManaRegen += base1;
|
||||
break;
|
||||
case SE_ManaPool:
|
||||
newbon->Mana += base1;
|
||||
break;
|
||||
case SE_ItemManaRegenCapIncrease:
|
||||
newbon->ItemManaRegenCap += base1;
|
||||
break;
|
||||
@ -782,8 +780,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_SetBreathLevel:
|
||||
break;
|
||||
case SE_RaiseStatCap:
|
||||
switch(base2)
|
||||
{
|
||||
switch (base2) {
|
||||
// are these #define'd somewhere?
|
||||
case 0: // str
|
||||
newbon->STRCapMod += base1;
|
||||
@ -826,8 +823,6 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SE_PetDiscipline2:
|
||||
break;
|
||||
case SE_SpellSlotIncrease:
|
||||
break;
|
||||
case SE_MysticalAttune:
|
||||
@ -939,8 +934,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->CombatStability += base1;
|
||||
break;
|
||||
case SE_AddSingingMod:
|
||||
switch (base2)
|
||||
{
|
||||
switch (base2) {
|
||||
case ItemTypeWindInstrument:
|
||||
newbon->windMod += base1;
|
||||
break;
|
||||
@ -1043,8 +1037,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->CrippBlowChance += base1;
|
||||
break;
|
||||
|
||||
case SE_HitChance:
|
||||
{
|
||||
case SE_HitChance: {
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (base2 == ALL_SKILLS)
|
||||
newbon->HitChanceEffect[HIGHEST_SKILL + 1] += base1;
|
||||
else
|
||||
@ -1052,16 +1048,16 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
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)
|
||||
newbon->SpellOnKill[i+2] = GetLevel() - 15; //AA specifiy "non-trivial"
|
||||
newbon->SpellOnKill[i + 2] =
|
||||
GetLevel() - 15; // AA specifiy "non-trivial"
|
||||
else
|
||||
newbon->SpellOnKill[i + 2] = 0;
|
||||
|
||||
@ -1071,10 +1067,8 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
|
||||
case SE_SpellOnDeath:
|
||||
for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2)
|
||||
{
|
||||
if(!newbon->SpellOnDeath[i])
|
||||
{
|
||||
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;
|
||||
@ -1085,31 +1079,32 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_TriggerOnCast:
|
||||
|
||||
for(int i = 0; i < MAX_SPELL_TRIGGER; i++)
|
||||
{
|
||||
if (newbon->SpellTriggers[i] == aaid)
|
||||
for (int i = 0; i < MAX_SPELL_TRIGGER; i++) {
|
||||
if (newbon->SpellTriggers[i] == rank.id)
|
||||
break;
|
||||
|
||||
if(!newbon->SpellTriggers[i])
|
||||
{
|
||||
//Save the 'aaid' of each triggerable effect to an array
|
||||
newbon->SpellTriggers[i] = aaid;
|
||||
if (!newbon->SpellTriggers[i]) {
|
||||
// Save the 'rank.id' of each triggerable effect to an array
|
||||
newbon->SpellTriggers[i] = rank.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_CriticalHitChance:
|
||||
{
|
||||
case SE_CriticalHitChance: {
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (base2 == ALL_SKILLS)
|
||||
newbon->CriticalHitChance[HIGHEST_SKILL + 1] += base1;
|
||||
else
|
||||
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)
|
||||
if (base2 == ALL_SKILLS)
|
||||
newbon->CritDmgMob[HIGHEST_SKILL + 1] += base1;
|
||||
@ -1118,8 +1113,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_CriticalSpellChance:
|
||||
{
|
||||
case SE_CriticalSpellChance: {
|
||||
newbon->CriticalSpellChance += base1;
|
||||
|
||||
if (base2 > newbon->SpellCritDmgIncNoStack)
|
||||
@ -1128,17 +1122,19 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
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:
|
||||
{
|
||||
case SE_SkillDamageAmount: {
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (base2 == ALL_SKILLS)
|
||||
newbon->SkillDamageAmount[HIGHEST_SKILL + 1] += base1;
|
||||
else
|
||||
@ -1146,16 +1142,18 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SpecialAttackKBProc:
|
||||
{
|
||||
case SE_SkillAttackProc: {
|
||||
// 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
|
||||
newbon->SkillAttackProc[0] = base1; // Chance base 1000 = 100% proc rate
|
||||
newbon->SkillAttackProc[1] = base2; // Skill to Proc Off
|
||||
newbon->SkillAttackProc[2] = rank.spell; // spell to proc
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DamageModifier:
|
||||
{
|
||||
case SE_DamageModifier: {
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (base2 == ALL_SKILLS)
|
||||
newbon->DamageModifier[HIGHEST_SKILL + 1] += base1;
|
||||
else
|
||||
@ -1163,8 +1161,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DamageModifier2:
|
||||
{
|
||||
case SE_DamageModifier2: {
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (base2 == ALL_SKILLS)
|
||||
newbon->DamageModifier2[HIGHEST_SKILL + 1] += base1;
|
||||
else
|
||||
@ -1172,21 +1172,19 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SlayUndead:
|
||||
{
|
||||
case SE_SlayUndead: {
|
||||
if (newbon->SlayUndead[1] < base1)
|
||||
newbon->SlayUndead[0] = base1; // Rate
|
||||
newbon->SlayUndead[1] = base2; // Damage Modifier
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DoubleRiposte:
|
||||
{
|
||||
case SE_DoubleRiposte: {
|
||||
newbon->DoubleRiposte += base1;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_GiveDoubleRiposte:
|
||||
{
|
||||
case SE_GiveDoubleRiposte: {
|
||||
// 0=Regular Riposte 1=Skill Attack Riposte 2=Skill
|
||||
if (base2 == 0) {
|
||||
if (newbon->GiveDoubleRiposte[0] < base1)
|
||||
@ -1203,8 +1201,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
// 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:
|
||||
{
|
||||
case SE_RaiseSkillCap: {
|
||||
if (newbon->RaiseSkillCap[0] < base1) {
|
||||
newbon->RaiseSkillCap[0] = base1; // value
|
||||
newbon->RaiseSkillCap[1] = base2; // skill
|
||||
@ -1212,41 +1209,34 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_MasteryofPast:
|
||||
{
|
||||
case SE_MasteryofPast: {
|
||||
if (newbon->MasteryofPast < base1)
|
||||
newbon->MasteryofPast = base1;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_CastingLevel2:
|
||||
case SE_CastingLevel:
|
||||
{
|
||||
case SE_CastingLevel: {
|
||||
newbon->effective_casting_level += base1;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DivineSave:
|
||||
{
|
||||
if(newbon->DivineSaveChance[0] < base1)
|
||||
{
|
||||
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+1] && (newbon->SEResist[e] == base2) && (newbon->SEResist[e+1] < base1)){
|
||||
case SE_SpellEffectResistChance: {
|
||||
for (int e = 0; e < MAX_RESISTABLE_EFFECTS * 2; e += 2) {
|
||||
if (newbon->SEResist[e + 1] && (newbon->SEResist[e] == base2) &&
|
||||
(newbon->SEResist[e + 1] < base1)) {
|
||||
newbon->SEResist[e] = base2; // Spell Effect ID
|
||||
newbon->SEResist[e + 1] = base1; // Resist Chance
|
||||
break;
|
||||
}
|
||||
else if (!newbon->SEResist[e+1]){
|
||||
} else if (!newbon->SEResist[e + 1]) {
|
||||
newbon->SEResist[e] = base2; // Spell Effect ID
|
||||
newbon->SEResist[e + 1] = base1; // Resist Chance
|
||||
break;
|
||||
@ -1255,8 +1245,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_MitigateDamageShield:
|
||||
{
|
||||
case SE_MitigateDamageShield: {
|
||||
if (base1 < 0)
|
||||
base1 = base1 * (-1);
|
||||
|
||||
@ -1264,8 +1253,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_FinishingBlow:
|
||||
{
|
||||
case SE_FinishingBlow: {
|
||||
// base1 = chance, base2 = damage
|
||||
if (newbon->FinishingBlow[1] < base2) {
|
||||
newbon->FinishingBlow[0] = base1;
|
||||
@ -1274,8 +1262,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_FinishingBlowLvl:
|
||||
{
|
||||
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;
|
||||
@ -1300,8 +1287,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->HealRate += base1;
|
||||
break;
|
||||
|
||||
case SE_MeleeLifetap:
|
||||
{
|
||||
case SE_MeleeLifetap: {
|
||||
|
||||
if ((base1 < 0) && (newbon->MeleeLifetap > base1))
|
||||
newbon->MeleeLifetap = base1;
|
||||
@ -1331,8 +1317,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->Metabolism += base1;
|
||||
break;
|
||||
|
||||
case SE_ImprovedReclaimEnergy:
|
||||
{
|
||||
case SE_ImprovedReclaimEnergy: {
|
||||
if ((base1 < 0) && (newbon->ImprovedReclaimEnergy > base1))
|
||||
newbon->ImprovedReclaimEnergy = base1;
|
||||
|
||||
@ -1341,8 +1326,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_HeadShot:
|
||||
{
|
||||
case SE_HeadShot: {
|
||||
if (newbon->HeadShot[1] < base2) {
|
||||
newbon->HeadShot[0] = base1;
|
||||
newbon->HeadShot[1] = base2;
|
||||
@ -1350,15 +1334,13 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_HeadShotLevel:
|
||||
{
|
||||
case SE_HeadShotLevel: {
|
||||
if (newbon->HSLevel < base1)
|
||||
newbon->HSLevel = base1;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Assassinate:
|
||||
{
|
||||
case SE_Assassinate: {
|
||||
if (newbon->Assassinate[1] < base2) {
|
||||
newbon->Assassinate[0] = base1;
|
||||
newbon->Assassinate[1] = base2;
|
||||
@ -1366,8 +1348,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_AssassinateLevel:
|
||||
{
|
||||
case SE_AssassinateLevel: {
|
||||
if (newbon->AssassinateLevel < base1)
|
||||
newbon->AssassinateLevel = base1;
|
||||
break;
|
||||
@ -1377,12 +1358,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->PetMeleeMitigation += base1;
|
||||
break;
|
||||
|
||||
case SE_MeleeVulnerability:
|
||||
newbon->MeleeVulnerability += base1;
|
||||
break;
|
||||
|
||||
case SE_FactionModPct:
|
||||
{
|
||||
case SE_FactionModPct: {
|
||||
if ((base1 < 0) && (newbon->FactionModPct > base1))
|
||||
newbon->FactionModPct = base1;
|
||||
|
||||
@ -1396,19 +1372,21 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
|
||||
case SE_LimitToSkill: {
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (base1 <= HIGHEST_SKILL)
|
||||
newbon->LimitToSkill[base1] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SkillProc: {
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(newbon->SkillProc[e] && newbon->SkillProc[e] == aaid)
|
||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
||||
if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id)
|
||||
break; // Do not use the same aa id more than once.
|
||||
|
||||
else if (!newbon->SkillProc[e]) {
|
||||
newbon->SkillProc[e] = aaid;
|
||||
newbon->SkillProc[e] = rank.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1417,13 +1395,12 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_SkillProcSuccess: {
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid)
|
||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
||||
if (newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == rank.id)
|
||||
break; // Do not use the same spell id more than once.
|
||||
|
||||
else if (!newbon->SkillProcSuccess[e]) {
|
||||
newbon->SkillProcSuccess[e] = aaid;
|
||||
newbon->SkillProcSuccess[e] = rank.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1434,7 +1411,82 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->MeleeMitigationEffect -= base1;
|
||||
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 +1927,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_CriticalHitChance:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (AdditiveWornBonus) {
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value;
|
||||
@ -2078,6 +2133,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_HitChance:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
|
||||
if (AdditiveWornBonus){
|
||||
if(base2 == ALL_SKILLS)
|
||||
@ -2112,6 +2170,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_DamageModifier:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -2121,6 +2182,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_DamageModifier2:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -2130,6 +2194,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_MinDamageModifier:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -2203,6 +2270,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
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))
|
||||
new_bonus->Accuracy[HIGHEST_SKILL+1] = effect_value;
|
||||
|
||||
@ -2226,6 +2296,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
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.
|
||||
if (IsAISpellEffect && max){
|
||||
if(base2 == ALL_SKILLS)
|
||||
@ -2344,6 +2417,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_CriticalDamageMob:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -2360,6 +2436,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_SkillDamageAmount:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -2465,6 +2544,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_SkillDamageAmount2:
|
||||
{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if(base2 == ALL_SKILLS)
|
||||
new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value;
|
||||
else
|
||||
@ -2980,10 +3062,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
new_bonus->PetMeleeMitigation += effect_value;
|
||||
break;
|
||||
|
||||
case SE_MeleeVulnerability:
|
||||
new_bonus->MeleeVulnerability += effect_value;
|
||||
break;
|
||||
|
||||
case SE_Sanctuary:
|
||||
new_bonus->Sanctuary = true;
|
||||
break;
|
||||
@ -3003,6 +3081,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
break;
|
||||
|
||||
case SE_LimitToSkill:{
|
||||
// Bad data or unsupported new skill
|
||||
if (base2 > HIGHEST_SKILL)
|
||||
break;
|
||||
if (effect_value <= HIGHEST_SKILL){
|
||||
new_bonus->LimitToSkill[effect_value] = true;
|
||||
}
|
||||
@ -4560,12 +4641,6 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.FactionModPct = effect_value;
|
||||
break;
|
||||
|
||||
case SE_MeleeVulnerability:
|
||||
spellbonuses.MeleeVulnerability = effect_value;
|
||||
itembonuses.MeleeVulnerability = effect_value;
|
||||
aabonuses.MeleeVulnerability = effect_value;
|
||||
break;
|
||||
|
||||
case SE_IllusionPersistence:
|
||||
spellbonuses.IllusionPersistence = false;
|
||||
itembonuses.IllusionPersistence = false;
|
||||
|
||||
1753
zone/bot.cpp
1753
zone/bot.cpp
File diff suppressed because it is too large
Load Diff
18
zone/bot.h
18
zone/bot.h
@ -169,7 +169,6 @@ public:
|
||||
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
|
||||
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
|
||||
virtual float GetProcChances(float ProcBonus, uint16 hand);
|
||||
virtual bool AvoidDamage(Mob* other, int32 &damage, bool CanRiposte);
|
||||
virtual int GetMonkHandToHandDamage(void);
|
||||
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
|
||||
virtual void DoRiposte(Mob* defender);
|
||||
@ -314,11 +313,12 @@ public:
|
||||
virtual float GetAOERange(uint16 spell_id);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
||||
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 IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||
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
|
||||
bool MesmerizeTarget(Mob* target);
|
||||
@ -448,12 +448,8 @@ public:
|
||||
bool IsBotWISCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN); }
|
||||
bool CanHeal();
|
||||
int GetRawACNoShield(int &shield_ac);
|
||||
void LoadAAs();
|
||||
uint32 GetAA(uint32 aa_id);
|
||||
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
|
||||
bool GetHasBeenSummoned() { return _hasBeenSummoned; }
|
||||
const glm::vec3 GetPreSummonLocation() const { return m_PreSummonLocation; }
|
||||
bool GetGroupMessagesOn() { return _groupMessagesOn; }
|
||||
bool GetInHealRotation() { return _isInHealRotation; }
|
||||
bool GetHealRotationActive() { return (GetInHealRotation() && _isHealRotationActive); }
|
||||
bool GetHealRotationUseFastHeals() { return _healRotationUseFastHeals; }
|
||||
@ -539,7 +535,6 @@ public:
|
||||
void SetDisciplineRecastTimer(int timer_index, int32 recast_delay);
|
||||
void SetHasBeenSummoned(bool s);
|
||||
void SetPreSummonLocation(const glm::vec3& location) { m_PreSummonLocation = location; }
|
||||
void SetGroupMessagesOn(bool groupMessagesOn) { _groupMessagesOn = groupMessagesOn; }
|
||||
void SetInHealRotation( bool inRotation ) { _isInHealRotation = inRotation; }
|
||||
void SetHealRotationActive( bool isActive ) { _isHealRotationActive = isActive; }
|
||||
void SetHealRotationUseFastHeals( bool useFastHeals ) { _healRotationUseFastHeals = useFastHeals; }
|
||||
@ -553,6 +548,8 @@ public:
|
||||
void SetBardUseOutOfCombatSongs(bool useOutOfCombatSongs) { _bardUseOutOfCombatSongs = useOutOfCombatSongs;}
|
||||
void SetShowHelm(bool showhelm) { _showhelm = showhelm; }
|
||||
|
||||
std::string CreateSayLink(Client* botOwner, const char* message, const char* name);
|
||||
|
||||
// Class Destructors
|
||||
virtual ~Bot();
|
||||
|
||||
@ -564,7 +561,7 @@ protected:
|
||||
virtual bool CheckBotDoubleAttack(bool Triple = false);
|
||||
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 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 bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
|
||||
virtual float GetMaxMeleeRangeToTarget(Mob* target);
|
||||
@ -608,7 +605,6 @@ private:
|
||||
bool _hasBeenSummoned;
|
||||
glm::vec3 m_PreSummonLocation;
|
||||
uint8 _spellCastingChances[MaxStances][MaxSpellTypes];
|
||||
bool _groupMessagesOn;
|
||||
bool _isInHealRotation;
|
||||
bool _isHealRotationActive;
|
||||
bool _healRotationUseFastHeals;
|
||||
@ -646,12 +642,12 @@ private:
|
||||
uint8 _baseGender; // Bots gender. Necessary to preserve the original value otherwise it can be changed by illusions.
|
||||
|
||||
// Class Methods
|
||||
void LoadAAs();
|
||||
int32 acmod();
|
||||
void GenerateBaseStats();
|
||||
void GenerateAppearance();
|
||||
void GenerateArmorClass();
|
||||
int32 GenerateBaseHitPoints();
|
||||
void GenerateAABonuses(StatBonuses* newbon);
|
||||
int32 GenerateBaseManaPoints();
|
||||
void GenerateSpecialAttacks();
|
||||
void SetBotID(uint32 botID);
|
||||
|
||||
@ -75,7 +75,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
|
||||
MakeAnyLenString(&gmsg, "Attempting to mez %s.", addMob->GetCleanName());
|
||||
|
||||
if(gmsg && GetGroupMessagesOn())
|
||||
if(gmsg)
|
||||
BotGroupSay(this, gmsg);
|
||||
}
|
||||
}
|
||||
@ -262,7 +262,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
}
|
||||
}
|
||||
|
||||
if(gmsg && GetGroupMessagesOn())
|
||||
if(gmsg)
|
||||
BotGroupSay(this, gmsg);
|
||||
}
|
||||
}
|
||||
@ -793,7 +793,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
|
||||
MakeAnyLenString(&gmsg, "Attempting to slow %s.", tar->GetCleanName());
|
||||
|
||||
if(gmsg && GetGroupMessagesOn())
|
||||
if(gmsg)
|
||||
BotGroupSay(this, gmsg);
|
||||
}
|
||||
}
|
||||
|
||||
132
zone/client.cpp
132
zone/client.cpp
@ -176,7 +176,6 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
admin = 0;
|
||||
lsaccountid = 0;
|
||||
shield_target = nullptr;
|
||||
SQL_log = nullptr;
|
||||
guild_id = GUILD_NONE;
|
||||
guildrank = 0;
|
||||
GuildBanker = false;
|
||||
@ -198,6 +197,7 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
SetTarget(0);
|
||||
auto_attack = false;
|
||||
auto_fire = false;
|
||||
runmode = false;
|
||||
linkdead_timer.Disable();
|
||||
zonesummon_id = 0;
|
||||
zonesummon_ignorerestrictions = 0;
|
||||
@ -440,7 +440,7 @@ void Client::SendZoneInPackets()
|
||||
|
||||
//Send AA Exp packet:
|
||||
if (GetLevel() >= 51)
|
||||
SendAAStats();
|
||||
SendAlternateAdvancementStats();
|
||||
|
||||
// Send exp packets
|
||||
outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct));
|
||||
@ -457,7 +457,7 @@ void Client::SendZoneInPackets()
|
||||
}
|
||||
safe_delete(outapp);
|
||||
|
||||
SendAATimers();
|
||||
SendAlternateAdvancementTimers();
|
||||
|
||||
outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct));
|
||||
ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer;
|
||||
@ -525,47 +525,38 @@ void Client::ReportConnectingState() {
|
||||
}
|
||||
|
||||
bool Client::SaveAA() {
|
||||
int first_entry = 0;
|
||||
std::string rquery;
|
||||
/* Save Player AA */
|
||||
std::string iquery;
|
||||
int spentpoints = 0;
|
||||
for (int a = 0; a < MAX_PP_AA_ARRAY; a++) {
|
||||
uint32 points = aa[a]->value;
|
||||
if (points > HIGHEST_AA_VALUE) {
|
||||
aa[a]->value = HIGHEST_AA_VALUE;
|
||||
points = HIGHEST_AA_VALUE;
|
||||
}
|
||||
if (points > 0) {
|
||||
SendAA_Struct* curAA = zone->FindAA(aa[a]->AA - aa[a]->value + 1);
|
||||
if (curAA) {
|
||||
for (int rank = 0; rank<points; rank++) {
|
||||
std::map<uint32, AALevelCost_Struct>::iterator RequiredLevel = AARequiredLevelAndCost.find(aa[a]->AA - aa[a]->value + 1 + rank);
|
||||
if (RequiredLevel != AARequiredLevelAndCost.end()) {
|
||||
spentpoints += RequiredLevel->second.Cost;
|
||||
}
|
||||
else
|
||||
spentpoints += (curAA->cost + (curAA->cost_inc * rank));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
int i = 0;
|
||||
for(auto &rank : aa_ranks) {
|
||||
AA::Ability *ability = zone->GetAlternateAdvancementAbility(rank.first);
|
||||
if(!ability)
|
||||
continue;
|
||||
|
||||
if(rank.second.first > 0) {
|
||||
AA::Rank *r = ability->GetRankByPointsSpent(rank.second.first);
|
||||
|
||||
if(!r)
|
||||
continue;
|
||||
|
||||
spentpoints += r->total_cost;
|
||||
|
||||
if(i == 0) {
|
||||
iquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)"
|
||||
" VALUES (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second);
|
||||
} else {
|
||||
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 */
|
||||
rquery = StringFormat("DELETE FROM `character_alternate_abilities` WHERE `id` = %u AND `slot` > %d", character_id, highest);
|
||||
|
||||
m_pp.aapoints_spent = spentpoints + m_epp.expended_aa;
|
||||
|
||||
if(iquery.length() > 0) {
|
||||
database.QueryDatabase(iquery);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -8040,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) {
|
||||
int slot = m_inv.GetSlotByItemInst(inst);
|
||||
if(slot != -1) {
|
||||
@ -8638,3 +8579,16 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
|
||||
QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::SendHPUpdateMarquee(){
|
||||
if (!RuleB(Character, MarqueeHPUpdates))
|
||||
return;
|
||||
|
||||
/* Health Update Marquee Display: Custom*/
|
||||
uint32 health_percentage = (uint32)(this->cur_hp * 100 / this->max_hp);
|
||||
if (health_percentage == 100)
|
||||
return;
|
||||
|
||||
std::string health_update_notification = StringFormat("Health: %u%%", health_percentage);
|
||||
this->SendMarqueeMessage(15, 510, 0, 3000, 3000, health_update_notification);
|
||||
}
|
||||
|
||||
@ -45,7 +45,6 @@ struct Item_Struct;
|
||||
#include "../common/item_struct.h"
|
||||
#include "../common/clientversions.h"
|
||||
|
||||
#include "aa.h"
|
||||
#include "common.h"
|
||||
#include "merc.h"
|
||||
#include "mob.h"
|
||||
@ -227,6 +226,7 @@ public:
|
||||
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
|
||||
virtual void SetAttackTimer();
|
||||
float GetQuiverHaste();
|
||||
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
|
||||
|
||||
void AI_Init();
|
||||
void AI_Start(uint32 iMoveDelay = 0);
|
||||
@ -541,7 +541,6 @@ public:
|
||||
|
||||
bool Flurry();
|
||||
bool Rampage();
|
||||
void DurationRampage(uint32 duration);
|
||||
|
||||
inline uint32 GetEXP() const { return m_pp.exp; }
|
||||
|
||||
@ -623,6 +622,7 @@ public:
|
||||
inline uint32 AccountID() const { return account_id; }
|
||||
|
||||
inline const char* AccountName()const { return account_name; }
|
||||
inline int GetAccountCreation() const { return account_creation; }
|
||||
inline int16 Admin() const { return admin; }
|
||||
inline uint32 CharacterID() const { return character_id; }
|
||||
void UpdateAdmin(bool iFromDB = true);
|
||||
@ -759,45 +759,35 @@ public:
|
||||
|
||||
inline PTimerList &GetPTimers() { return(p_timers); }
|
||||
|
||||
//AA Methods
|
||||
void SendAAList();
|
||||
void ResetAA();
|
||||
void SendClearAA();
|
||||
void SendAA(uint32 id, int seq=1);
|
||||
void SendPreviousAA(uint32 id, int seq=1);
|
||||
void BuyAA(AA_Action* action);
|
||||
//this function is used by some AA stuff
|
||||
void MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing);
|
||||
void SetAATitle(const char *Title);
|
||||
void SetTitleSuffix(const char *txt);
|
||||
inline uint32 GetMaxAAXP(void) const { return max_AAXP; }
|
||||
inline uint32 GetAAXP() const { return m_pp.expAA; }
|
||||
void SendAAStats();
|
||||
void SendAATable();
|
||||
void SendAATimers();
|
||||
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(); }
|
||||
//New AA Methods
|
||||
void SendAlternateAdvancementRank(int aa_id, int level);
|
||||
void SendAlternateAdvancementTable();
|
||||
void SendAlternateAdvancementStats();
|
||||
void PurchaseAlternateAdvancementRank(int rank_id);
|
||||
bool GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost = false);
|
||||
void IncrementAlternateAdvancementRank(int rank_id);
|
||||
void ActivateAlternateAdvancementAbility(int rank_id, int target_id);
|
||||
void SendAlternateAdvancementPoints();
|
||||
void SendAlternateAdvancementTimer(int ability, int begin, int end);
|
||||
void SendAlternateAdvancementTimers();
|
||||
void ResetAlternateAdvancementTimer(int ability);
|
||||
void ResetAlternateAdvancementTimers();
|
||||
|
||||
void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAlternateAdvancementStats(); }
|
||||
void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAlternateAdvancementStats(); }
|
||||
int GetAAPoints() { return m_pp.aapoints; }
|
||||
int GetSpentAA() { return m_pp.aapoints_spent; }
|
||||
|
||||
//old AA methods that we still use
|
||||
void ResetAA();
|
||||
void RefundAA();
|
||||
void IncrementAA(int aa_id);
|
||||
int32 GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2);
|
||||
int32 GetAAEffectid(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, true, false,false); }
|
||||
int32 GetAABase1(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, true,false); }
|
||||
int32 GetAABase2(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, false,true); }
|
||||
void SendClearAA();
|
||||
inline uint32 GetMaxAAXP(void) const { return max_AAXP; }
|
||||
inline uint32 GetAAXP() const { return m_pp.expAA; }
|
||||
int16 CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id);
|
||||
void SetAATitle(const char *Title);
|
||||
void SetTitleSuffix(const char *txt);
|
||||
void MemorizeSpell(uint32 slot, uint32 spellid, uint32 scribing);
|
||||
int32 acmod();
|
||||
|
||||
// Item methods
|
||||
@ -898,8 +888,10 @@ public:
|
||||
bool CheckTradeLoreConflict(Client* other);
|
||||
void LinkDead();
|
||||
void Insight(uint32 t_id);
|
||||
bool CheckDoubleAttack(bool tripleAttack = false);
|
||||
bool CheckDoubleAttack();
|
||||
bool CheckTripleAttack();
|
||||
bool CheckDoubleRangedAttack();
|
||||
bool CheckDualWield();
|
||||
|
||||
//remove charges/multiple objects from inventory:
|
||||
//bool DecreaseByType(uint32 type, uint8 amt);
|
||||
@ -1157,6 +1149,7 @@ public:
|
||||
void RemoveAutoXTargets();
|
||||
void ShowXTargets(Client *c);
|
||||
bool GroupFollow(Client* inviter);
|
||||
inline bool GetRunMode() const { return runmode; }
|
||||
|
||||
void InitializeMercInfo();
|
||||
bool CheckCanSpawnMerc(uint32 template_id);
|
||||
@ -1260,6 +1253,9 @@ public:
|
||||
void QuestReward(Mob* target, uint32 copper = 0, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0, uint32 itemid = 0, uint32 exp = 0, bool faction = false);
|
||||
|
||||
void ResetHPUpdateTimer() { hpupdate_timer.Start(); }
|
||||
|
||||
void SendHPUpdateMarquee();
|
||||
|
||||
protected:
|
||||
friend class Mob;
|
||||
void CalcItemBonuses(StatBonuses* newbon);
|
||||
@ -1267,8 +1263,6 @@ protected:
|
||||
void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false);
|
||||
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
|
||||
void CalcEdibleBonuses(StatBonuses* newbon);
|
||||
void CalcAABonuses(StatBonuses* newbon);
|
||||
void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon);
|
||||
void ProcessItemCaps();
|
||||
void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true);
|
||||
bool client_data_loaded;
|
||||
@ -1276,6 +1270,8 @@ protected:
|
||||
int16 GetFocusEffect(focusType type, uint16 spell_id);
|
||||
uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id);
|
||||
|
||||
void FinishAlternateAdvancementPurchase(AA::Rank *rank, bool ignore_cost);
|
||||
|
||||
Mob* bind_sight_target;
|
||||
|
||||
glm::vec4 m_AutoAttackPosition;
|
||||
@ -1385,6 +1381,7 @@ private:
|
||||
bool AFK;
|
||||
bool auto_attack;
|
||||
bool auto_fire;
|
||||
bool runmode;
|
||||
uint8 gmspeed;
|
||||
bool medding;
|
||||
uint16 horseId;
|
||||
@ -1492,11 +1489,7 @@ private:
|
||||
|
||||
uint32 tribute_master_id;
|
||||
|
||||
FILE *SQL_log;
|
||||
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;
|
||||
uint8 npclevel;
|
||||
bool feigned;
|
||||
|
||||
@ -1121,7 +1121,7 @@ int32 Client::CalcMaxMana()
|
||||
switch (GetCasterClass()) {
|
||||
case 'I':
|
||||
case 'W': {
|
||||
max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement());
|
||||
max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement());
|
||||
break;
|
||||
}
|
||||
case 'N': {
|
||||
@ -1978,7 +1978,18 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id) const
|
||||
return 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...
|
||||
// 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.
|
||||
@ -2048,10 +2059,11 @@ uint32 Mob::GetInstrumentMod(uint16 spell_id) const
|
||||
effectmod = 10;
|
||||
return effectmod;
|
||||
}
|
||||
if (!RuleB(Character, UseSpellFileSongCap))
|
||||
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap;
|
||||
if (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;
|
||||
Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", GetName(), spell_id,
|
||||
effectmod, effectmodcap);
|
||||
|
||||
@ -389,6 +389,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_XTargetRequest] = &Client::Handle_OP_XTargetRequest;
|
||||
ConnectedOpcodes[OP_YellForHelp] = &Client::Handle_OP_YellForHelp;
|
||||
ConnectedOpcodes[OP_ZoneChange] = &Client::Handle_OP_ZoneChange;
|
||||
ConnectedOpcodes[OP_ResetAA] = &Client::Handle_OP_ResetAA;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
SendAATimers();
|
||||
SendAlternateAdvancementTimers();
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAAStats, 0);
|
||||
QueuePacket(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)
|
||||
{
|
||||
SendAAList();
|
||||
SendAlternateAdvancementTable();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1152,7 +1153,7 @@ void Client::Handle_Connect_OP_TGB(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app)
|
||||
{
|
||||
SendAATable();
|
||||
SendAlternateAdvancementPoints();
|
||||
}
|
||||
|
||||
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_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; }
|
||||
|
||||
/* Initialize AA's : Move to function eventually */
|
||||
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++)
|
||||
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++;
|
||||
if(RuleB(World, UseClientBasedExpansionSettings)) {
|
||||
m_pp.expansions = ExpansionFromClientVersion(GetClientVersion());
|
||||
}
|
||||
for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){
|
||||
uint32 id = aa[a]->AA;
|
||||
//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;
|
||||
else {
|
||||
m_pp.expansions = RuleI(World, ExpansionSettings);
|
||||
}
|
||||
|
||||
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) */
|
||||
aa_points[(id - aa[a]->value + 1)] = aa[a]->value;
|
||||
else
|
||||
aa_points[id] = aa[a]->value;
|
||||
if(!database.LoadAlternateAdvancement(this)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Error loading AA points for %s", GetName());
|
||||
}
|
||||
|
||||
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. */
|
||||
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());
|
||||
if (!p_timers.Load(&database)) {
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
AA_Action* action = (AA_Action*)app->pBuffer;
|
||||
|
||||
if (action->action == aaActionActivate) {//AA Hotkey
|
||||
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) {
|
||||
BuyAA(action);
|
||||
PurchaseAlternateAdvancementRank(action->ability);
|
||||
}
|
||||
else if (action->action == aaActionDisableEXP){ //Turn Off AA Exp
|
||||
if (m_epp.perAA > 0)
|
||||
Message_StringID(0, AA_OFF);
|
||||
|
||||
m_epp.perAA = 0;
|
||||
SendAAStats();
|
||||
SendAlternateAdvancementStats();
|
||||
}
|
||||
else if (action->action == aaActionSetEXP) {
|
||||
if (m_epp.perAA == 0)
|
||||
Message_StringID(0, AA_ON);
|
||||
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
|
||||
SendAAStats();
|
||||
SendAATable();
|
||||
SendAlternateAdvancementStats();
|
||||
SendAlternateAdvancementTable();
|
||||
}
|
||||
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)
|
||||
@ -3898,8 +3852,6 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos);
|
||||
|
||||
CastSpell(spell_to_cast, castspell->target_id, castspell->slot);
|
||||
}
|
||||
/* Spell Slot or Potion Belt Slot */
|
||||
@ -6056,7 +6008,7 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app)
|
||||
char *escSearchString = new char[129];
|
||||
database.DoEscapeString(escSearchString, gmscs->Name, strlen(gmscs->Name));
|
||||
|
||||
std::string query = StringFormat("SELECT charname, zoneid, x, y, z, time_of_death, rezzed, IsBurried "
|
||||
std::string query = StringFormat("SELECT charname, zoneid, x, y, z, time_of_death, is_rezzed, is_buried "
|
||||
"FROM character_corpses WheRE charname LIKE '%%%s%%' ORDER BY charname LIMIT %i",
|
||||
escSearchString, maxResults);
|
||||
safe_delete_array(escSearchString);
|
||||
@ -8852,7 +8804,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app)
|
||||
pack->WriteUInt32(QSG_LFGuild_UpdatePlayerInfo);
|
||||
pack->WriteUInt32(GetBaseClass());
|
||||
pack->WriteUInt32(GetLevel());
|
||||
pack->WriteUInt32(GetAAPointsSpent());
|
||||
pack->WriteUInt32(GetSpentAA());
|
||||
pack->WriteString(pts->Comment);
|
||||
pack->WriteUInt32(pts->Toggle);
|
||||
pack->WriteUInt32(pts->TimeZone);
|
||||
@ -11836,6 +11788,18 @@ void Client::Handle_OP_SetGuildMOTD(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_SetRunMode(const EQApplicationPacket *app)
|
||||
{
|
||||
if (app->size < sizeof(SetRunMode_Struct)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Received invalid sized "
|
||||
"OP_SetRunMode: got %d, expected %d", app->size,
|
||||
sizeof(SetRunMode_Struct));
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
SetRunMode_Struct* rms = (SetRunMode_Struct*)app->pBuffer;
|
||||
if (rms->mode)
|
||||
runmode = true;
|
||||
else
|
||||
runmode = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -14216,9 +14180,12 @@ void Client::Handle_OP_YellForHelp(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app)
|
||||
void Client::Handle_OP_ResetAA(const EQApplicationPacket *app)
|
||||
{
|
||||
if(Admin() >= 50) {
|
||||
Message(0, "Resetting AA points.");
|
||||
ResetAA();
|
||||
}
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
@ -295,3 +295,4 @@
|
||||
void Handle_OP_XTargetRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_YellForHelp(const EQApplicationPacket *app);
|
||||
void Handle_OP_ZoneChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_ResetAA(const EQApplicationPacket *app);
|
||||
|
||||
@ -391,73 +391,12 @@ bool Client::Process() {
|
||||
}
|
||||
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);
|
||||
TryWeaponProc(wpn, auto_attack_target, MainPrimary);
|
||||
|
||||
bool tripleAttackSuccess = false;
|
||||
if( auto_attack_target && CanThisClassDoubleAttack() ) {
|
||||
|
||||
CheckIncreaseSkill(SkillDoubleAttack, auto_attack_target, -10);
|
||||
if(CheckDoubleAttack()) {
|
||||
//should we allow rampage on double attack?
|
||||
if(CheckAAEffect(aaEffectRampage)) {
|
||||
DoAttackRounds(auto_attack_target, MainPrimary);
|
||||
if (CheckAATimer(aaTimerRampage))
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,32 +428,12 @@ bool Client::Process() {
|
||||
//you can't see your target
|
||||
}
|
||||
else if(auto_attack_target->GetHP() > -10) {
|
||||
float DualWieldProbability = 0.0f;
|
||||
|
||||
int16 Ambidexterity = aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity;
|
||||
DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max
|
||||
int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance;
|
||||
DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f;
|
||||
|
||||
float random = zone->random.Real(0, 1);
|
||||
CheckIncreaseSkill(SkillDualWield, auto_attack_target, -10);
|
||||
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
|
||||
}
|
||||
if (CheckDualWield()) {
|
||||
ItemInst *wpn = GetInv().GetItem(MainSecondary);
|
||||
TryWeaponProc(wpn, auto_attack_target, MainSecondary);
|
||||
|
||||
if( CanThisClassDoubleAttack() && CheckDoubleAttack()) {
|
||||
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
|
||||
}
|
||||
}
|
||||
DoAttackRounds(auto_attack_target, MainSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -522,9 +441,7 @@ bool Client::Process() {
|
||||
if (position_timer.Check()) {
|
||||
if (IsAIControlled())
|
||||
{
|
||||
if(IsMoving())
|
||||
SendPosUpdate(2);
|
||||
else
|
||||
if(!IsMoving())
|
||||
{
|
||||
animation = 0;
|
||||
m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w);
|
||||
|
||||
164
zone/command.cpp
164
zone/command.cpp
@ -168,10 +168,10 @@ 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("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("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("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("aug", nullptr, 250, command_augmentitem) ||
|
||||
command_add("ban", "[name] [reason]- Ban by character name", 150, command_ban) ||
|
||||
command_add("beard", "- Change the beard of your target", 80, command_beard) ||
|
||||
command_add("beardcolor", "- Change the beard color of your target", 80, command_beardcolor) ||
|
||||
@ -218,11 +218,14 @@ int command_init(void) {
|
||||
command_add("flagedit", "- Edit zone flags on your target", 100, command_flagedit) ||
|
||||
command_add("flags", "- displays the flags of you or your target", 0, command_flags) ||
|
||||
command_add("flymode", "[0/1/2] - Set your or your player target's flymode to off/on/levitate", 50, command_flymode) ||
|
||||
command_add("fn", nullptr, 100, command_findnpctype) ||
|
||||
command_add("fov", "- Check wether you're behind or in your target's field of view", 80, command_fov) ||
|
||||
command_add("freeze", "- Freeze your target", 80, command_freeze) ||
|
||||
command_add("fs", nullptr, 50, command_findspell) ||
|
||||
command_add("fz", nullptr, 100, command_findzone) ||
|
||||
command_add("gassign", "[id] - Assign targetted NPC to predefined wandering grid id", 100, command_gassign) ||
|
||||
command_add("gender", "[0/1/2] - Change your or your target's gender to male/female/neuter", 50, command_gender) ||
|
||||
command_add("getplayerburriedcorpsecount", "- Get the target's total number of burried player corpses.", 100, command_getplayerburriedcorpsecount) ||
|
||||
command_add("getplayerburiedcorpsecount", "- Get the target's total number of buried player corpses.", 100, command_getplayerburiedcorpsecount) ||
|
||||
command_add("getvariable", "[varname] - Get the value of a variable from the database", 200, command_getvariable) ||
|
||||
command_add("gi", nullptr,200, command_giveitem) ||
|
||||
command_add("ginfo", "- get group info on target.", 20, command_ginfo) ||
|
||||
@ -275,7 +278,6 @@ int command_init(void) {
|
||||
command_add("los", nullptr,0, command_checklos) ||
|
||||
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("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("memspell", "[slotid] [spellid] - Memorize spellid in the specified slot", 50, command_memspell) ||
|
||||
command_add("merchant_close_shop", "Closes a merchant shop", 100, command_merchantcloseshop) ||
|
||||
@ -324,6 +326,7 @@ int command_init(void) {
|
||||
command_add("raidloot", "LEADER|GROUPLEADER|SELECTED|ALL - Sets your raid loot settings if you have permission to do so.", 0, command_raidloot) ||
|
||||
command_add("randomfeatures", "- Temporarily randomizes the Facial Features of your target", 80, command_randomfeatures) ||
|
||||
command_add("refreshgroup", "- Refreshes Group.", 0, command_refreshgroup) ||
|
||||
command_add("reloadaa", "Reloads AA data", 200, command_reloadaa) ||
|
||||
command_add("reloadallrules", "Executes a reload of all rules.", 80, command_reloadallrules) ||
|
||||
command_add("reloademote", "Reloads NPC Emotes", 80, command_reloademote) ||
|
||||
command_add("reloadlevelmods", nullptr,255, command_reloadlevelmods) ||
|
||||
@ -336,8 +339,10 @@ int command_init(void) {
|
||||
command_add("reloadzonepoints", "- Reload zone points from database", 150, command_reloadzps) ||
|
||||
command_add("reloadzps", nullptr,0, command_reloadzps) ||
|
||||
command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) ||
|
||||
command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, 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("rq", nullptr, 150, command_reloadqst) ||
|
||||
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("scribespell", "[spellid] - Scribe specified spell in your target's spell book.", 180, command_scribespell) ||
|
||||
@ -386,7 +391,7 @@ int command_init(void) {
|
||||
command_add("spon", "- Sends OP_MemorizeSpell", 80, command_spon) ||
|
||||
command_add("stun", "[duration] - Stuns you or your target for duration", 100, command_stun) ||
|
||||
command_add("summon", "[charname] - Summons your player/npc/corpse target, or charname if specified", 80, command_summon) ||
|
||||
command_add("summonburriedplayercorpse", "- Summons the target's oldest burried corpse, if any exist.", 100, command_summonburriedplayercorpse) ||
|
||||
command_add("summonburiedplayercorpse", "- Summons the target's oldest buried corpse, if any exist.", 100, command_summonburiedplayercorpse) ||
|
||||
command_add("summonitem", "[itemid] [charges] - Summon an item onto your cursor. Charges are optional.", 200, command_summonitem) ||
|
||||
command_add("suspend", "[name] [days] [reason] - Suspend by character name and for specificed number of days", 150, command_suspend) ||
|
||||
command_add("task", "(subcommand) - Task system commands", 150, command_task) ||
|
||||
@ -676,7 +681,7 @@ void command_incstat(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->Message(13,"Successfully reset %s's AAs", c->GetTarget()->GetName());
|
||||
}
|
||||
@ -1486,7 +1491,7 @@ void command_npcstats(Client *c, const Seperator *sep)
|
||||
c->Message(0, "Current HP: %i Max HP: %i", c->GetTarget()->GetHP(), c->GetTarget()->GetMaxHP());
|
||||
//c->Message(0, "Weapon Item Number: %s", c->GetTarget()->GetWeapNo());
|
||||
c->Message(0, "Gender: %i Size: %f Bodytype: %d", c->GetTarget()->GetGender(), c->GetTarget()->GetSize(), c->GetTarget()->GetBodyType());
|
||||
c->Message(0, "Runspeed: %i Walkspeed: %i", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed());
|
||||
c->Message(0, "Runspeed: %.3f Walkspeed: %.3f", static_cast<float>(0.025f * c->GetTarget()->GetRunspeed()), static_cast<float>(0.025f * c->GetTarget()->GetWalkspeed()));
|
||||
c->Message(0, "Spawn Group: %i Grid: %i", c->GetTarget()->CastToNPC()->GetSp2(), c->GetTarget()->CastToNPC()->GetGrid());
|
||||
c->Message(0, "EmoteID: %i", c->GetTarget()->CastToNPC()->GetEmoteID());
|
||||
c->GetTarget()->CastToNPC()->QueryLoot(c);
|
||||
@ -2299,7 +2304,7 @@ void command_setskill(Client *c, const Seperator *sep)
|
||||
Log.Out(Logs::General, Logs::Normal, "Set skill request from %s, target:%s skill_id:%i value:%i", c->GetName(), c->GetTarget()->GetName(), atoi(sep->arg[1]), atoi(sep->arg[2]) );
|
||||
int skill_num = atoi(sep->arg[1]);
|
||||
uint16 skill_value = atoi(sep->arg[2]);
|
||||
if(skill_num < HIGHEST_SKILL)
|
||||
if(skill_num <= HIGHEST_SKILL)
|
||||
c->GetTarget()->CastToClient()->SetSkill((SkillUseTypes)skill_num, skill_value);
|
||||
}
|
||||
}
|
||||
@ -4842,36 +4847,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)
|
||||
{
|
||||
if (!sep->IsNumber(1))
|
||||
@ -5586,16 +5561,23 @@ void command_setaapts(Client *c, const Seperator *sep)
|
||||
|
||||
if(sep->arg[1][0] == '\0' || sep->arg[2][0] == '\0')
|
||||
c->Message(0, "Usage: #setaapts <AA|group|raid> <new AA points value>");
|
||||
else if(atoi(sep->arg[2]) <= 0 || atoi(sep->arg[2]) > 200)
|
||||
c->Message(0, "You must have a number greater than 0 for points and no more than 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 5000.");
|
||||
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")) {
|
||||
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 {
|
||||
t->SetEXP(t->GetEXP(),t->GetMaxAAXP()*atoi(sep->arg[2]),false);
|
||||
t->SendAAStats();
|
||||
t->SendAATable();
|
||||
t->GetPP().aapoints = atoi(sep->arg[2]);
|
||||
t->GetPP().expAA = 0;
|
||||
t->Message(MT_Experience, "Setting personal AA points to %u", t->GetPP().aapoints);
|
||||
t->SendAlternateAdvancementStats();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7678,56 +7660,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)
|
||||
{
|
||||
uint8 max_level, min_level;
|
||||
@ -7874,7 +7806,7 @@ void command_deletegraveyard(Client *c, const Seperator *sep)
|
||||
return;
|
||||
}
|
||||
|
||||
void command_summonburriedplayercorpse(Client *c, const Seperator *sep)
|
||||
void command_summonburiedplayercorpse(Client *c, const Seperator *sep)
|
||||
{
|
||||
Client *t=c;
|
||||
|
||||
@ -7888,12 +7820,12 @@ void command_summonburriedplayercorpse(Client *c, const Seperator *sep)
|
||||
Corpse* PlayerCorpse = database.SummonBuriedCharacterCorpses(t->CharacterID(), t->GetZoneID(), zone->GetInstanceID(), t->GetPosition());
|
||||
|
||||
if(!PlayerCorpse)
|
||||
c->Message(0, "Your target doesn't have any burried corpses.");
|
||||
c->Message(0, "Your target doesn't have any buried corpses.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void command_getplayerburriedcorpsecount(Client *c, const Seperator *sep)
|
||||
void command_getplayerburiedcorpsecount(Client *c, const Seperator *sep)
|
||||
{
|
||||
Client *t=c;
|
||||
|
||||
@ -7907,9 +7839,9 @@ void command_getplayerburriedcorpsecount(Client *c, const Seperator *sep)
|
||||
uint32 CorpseCount = database.GetCharacterBuriedCorpseCount(t->CharacterID());
|
||||
|
||||
if(CorpseCount > 0)
|
||||
c->Message(0, "Your target has a total of %u burried corpses.", CorpseCount);
|
||||
c->Message(0, "Your target has a total of %u buried corpses.", CorpseCount);
|
||||
else
|
||||
c->Message(0, "Your target doesn't have any burried corpses.");
|
||||
c->Message(0, "Your target doesn't have any buried corpses.");
|
||||
|
||||
return;
|
||||
}
|
||||
@ -10658,6 +10590,38 @@ void command_mysqltest(Client *c, const Seperator *sep)
|
||||
Log.Out(Logs::General, Logs::Debug, "MySQL Test... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC);
|
||||
}
|
||||
|
||||
void command_resetaa_timer(Client *c, const Seperator *sep) {
|
||||
Client *target = nullptr;
|
||||
if(!c->GetTarget() || !c->GetTarget()->IsClient()) {
|
||||
target = c;
|
||||
} else {
|
||||
target = c->GetTarget()->CastToClient();
|
||||
}
|
||||
|
||||
if(sep->IsNumber(1))
|
||||
{
|
||||
int timer_id = atoi(sep->arg[1]);
|
||||
c->Message(0, "Reset of timer %i for %s", timer_id, c->GetName());
|
||||
c->ResetAlternateAdvancementTimer(timer_id);
|
||||
}
|
||||
else if(!strcasecmp(sep->arg[1], "all"))
|
||||
{
|
||||
c->Message(0, "Reset all timers for %s", c->GetName());
|
||||
c->ResetAlternateAdvancementTimers();
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Message(0, "usage: #resetaa_timer [all | timer_id]");
|
||||
}
|
||||
}
|
||||
|
||||
void command_reloadaa(Client *c, const Seperator *sep) {
|
||||
c->Message(0, "Reloading Alternate Advancement Data...");
|
||||
zone->LoadAlternateAdvancement();
|
||||
c->Message(0, "Alternate Advancement Data Reloaded");
|
||||
entity_list.SendAlternateAdvancementStats();
|
||||
}
|
||||
|
||||
void command_hotfix(Client *c, const Seperator *sep) {
|
||||
char hotfix[256] = { 0 };
|
||||
database.GetVariable("hotfix_name", hotfix, 256);
|
||||
|
||||
@ -216,7 +216,6 @@ void command_time(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);
|
||||
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_randomfeatures(Client *c, const Seperator *sep);
|
||||
void command_face(Client *c, const Seperator *sep);
|
||||
@ -276,13 +275,12 @@ void command_guildlist(Client *c, const Seperator *sep);
|
||||
void command_rules(Client *c, const Seperator *sep);
|
||||
void command_task(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_traindisc(Client *c, const Seperator *sep);
|
||||
void command_deletegraveyard(Client *c, const Seperator *sep);
|
||||
void command_setgraveyard(Client *c, const Seperator *sep);
|
||||
void command_getplayerburriedcorpsecount(Client *c, const Seperator *sep);
|
||||
void command_summonburriedplayercorpse(Client *c, const Seperator *sep);
|
||||
void command_getplayerburiedcorpsecount(Client *c, const Seperator *sep);
|
||||
void command_summonburiedplayercorpse(Client *c, const Seperator *sep);
|
||||
void command_unscribespell(Client *c, const Seperator *sep);
|
||||
void command_scribespell(Client *c, const Seperator *sep);
|
||||
void command_refreshgroup(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_mysqltest(Client *c, const Seperator *sep);
|
||||
void command_logs(Client *c, const Seperator *sep);
|
||||
void command_resetaa_timer(Client *c, const Seperator *sep);
|
||||
void command_reloadaa(Client *c, const Seperator *sep);
|
||||
void command_hotfix(Client *c, const Seperator *sep);
|
||||
|
||||
#ifdef EQPROFILE
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#define TARGET_RING_SPELL_SLOT 12
|
||||
#define DISCIPLINE_SPELL_SLOT 10
|
||||
#define ABILITY_SPELL_SLOT 9
|
||||
#define ALTERNATE_ABILITY_SPELL_SLOT 0xFF
|
||||
|
||||
//LOS Parameters:
|
||||
#define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from
|
||||
@ -400,7 +401,6 @@ struct StatBonuses {
|
||||
int32 Metabolism; // Food/drink consumption rates.
|
||||
bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others.
|
||||
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.
|
||||
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.
|
||||
@ -412,7 +412,7 @@ struct StatBonuses {
|
||||
int8 BaseMovementSpeed; // Adjust base run speed, does not stack with other movement bonuses.
|
||||
uint8 IncreaseRunSpeedCap; // Increase max run speed above cap.
|
||||
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
|
||||
int32 BindWound; // Increase amount of HP by percent.
|
||||
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.
|
||||
int32 PetMeleeMitigation; // Add AC to owner's pet.
|
||||
bool IllusionPersistence; // Causes illusions not to fade.
|
||||
uint16 extra_xtargets; // extra xtarget entries
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
||||
@ -835,7 +835,7 @@ bool Corpse::Process() {
|
||||
Save();
|
||||
player_corpse_depop = true;
|
||||
corpse_db_id = 0;
|
||||
Log.Out(Logs::General, Logs::None, "Tagged %s player corpse has burried.", this->GetName());
|
||||
Log.Out(Logs::General, Logs::None, "Tagged %s player corpse has buried.", this->GetName());
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::General, Logs::Error, "Unable to bury %s player corpse.", this->GetName());
|
||||
|
||||
@ -421,12 +421,6 @@ int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
|
||||
int tic_inc = 0;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
//Dook- Rampage and stuff for clients.
|
||||
// Rampage and stuff for clients. Normal and Duration rampages
|
||||
//NPCs handle it differently in Mob::Rampage
|
||||
void EntityList::AEAttack(Mob *attacker, float dist, int Hand, int count, bool IsFromSpell) {
|
||||
//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 */
|
||||
&& (DistanceSquared(curmob->GetPosition(), attacker->GetPosition()) <= dist2)
|
||||
) {
|
||||
if (!attacker->IsClient() || attacker->GetClass() == MONK || attacker->GetClass() == RANGER)
|
||||
attacker->Attack(curmob, Hand, false, false, IsFromSpell);
|
||||
else
|
||||
attacker->CastToClient()->DoAttackRounds(curmob, Hand, IsFromSpell);
|
||||
hit++;
|
||||
if (count != 0 && hit >= count)
|
||||
return;
|
||||
|
||||
@ -1748,18 +1748,18 @@ XS(XS__clear_zone_flag)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__summonburriedplayercorpse);
|
||||
XS(XS__summonburriedplayercorpse)
|
||||
XS(XS__summonburiedplayercorpse);
|
||||
XS(XS__summonburiedplayercorpse)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 5)
|
||||
Perl_croak(aTHX_ "Usage: summonburriedplayercorpse(char_id,dest_x,dest_y,dest_z,dest_heading)");
|
||||
Perl_croak(aTHX_ "Usage: summonburiedplayercorpse(char_id,dest_x,dest_y,dest_z,dest_heading)");
|
||||
|
||||
bool RETVAL;
|
||||
uint32 char_id = (int)SvIV(ST(0));
|
||||
auto position = glm::vec4((float)SvIV(ST(1)), (float)SvIV(ST(2)), (float)SvIV(ST(3)),(float)SvIV(ST(4)));
|
||||
|
||||
RETVAL = quest_manager.summonburriedplayercorpse(char_id, position);
|
||||
RETVAL = quest_manager.summonburiedplayercorpse(char_id, position);
|
||||
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
@ -1784,19 +1784,19 @@ XS(XS__summonallplayercorpses)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__getplayerburriedcorpsecount);
|
||||
XS(XS__getplayerburriedcorpsecount)
|
||||
XS(XS__getplayerburiedcorpsecount);
|
||||
XS(XS__getplayerburiedcorpsecount)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: getplayerburriedcorpsecount(char_id)");
|
||||
Perl_croak(aTHX_ "Usage: getplayerburiedcorpsecount(char_id)");
|
||||
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
uint32 char_id = (int)SvIV(ST(0));
|
||||
|
||||
RETVAL = quest_manager.getplayerburriedcorpsecount(char_id);
|
||||
RETVAL = quest_manager.getplayerburiedcorpsecount(char_id);
|
||||
XSprePUSH; PUSHu((IV)RETVAL);
|
||||
|
||||
XSRETURN(1);
|
||||
@ -3712,7 +3712,7 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file);
|
||||
newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file);
|
||||
newXS(strcpy(buf, "getlevel"), XS__getlevel, file);
|
||||
newXS(strcpy(buf, "getplayerburriedcorpsecount"), XS__getplayerburriedcorpsecount, file);
|
||||
newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file);
|
||||
newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file);
|
||||
newXS(strcpy(buf, "givecash"), XS__givecash, file);
|
||||
newXS(strcpy(buf, "gmmove"), XS__gmmove, file);
|
||||
@ -3802,7 +3802,7 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "stopalltimers"), XS__stopalltimers, file);
|
||||
newXS(strcpy(buf, "stoptimer"), XS__stoptimer, file);
|
||||
newXS(strcpy(buf, "summonallplayercorpses"), XS__summonallplayercorpses, file);
|
||||
newXS(strcpy(buf, "summonburriedplayercorpse"), XS__summonburriedplayercorpse, file);
|
||||
newXS(strcpy(buf, "summonburiedplayercorpse"), XS__summonburiedplayercorpse, file);
|
||||
newXS(strcpy(buf, "summonitem"), XS__summonitem, file);
|
||||
newXS(strcpy(buf, "surname"), XS__surname, file);
|
||||
newXS(strcpy(buf, "targlobal"), XS__targlobal, file);
|
||||
|
||||
@ -58,7 +58,6 @@ extern uint32 numclients;
|
||||
extern PetitionList petition_list;
|
||||
|
||||
extern char errorname[32];
|
||||
extern uint16 adverrornum;
|
||||
|
||||
Entity::Entity()
|
||||
{
|
||||
@ -4705,3 +4704,11 @@ void EntityList::StopMobAI()
|
||||
mob.second->AI_ShutDown();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::SendAlternateAdvancementStats() {
|
||||
for(auto &c : client_list) {
|
||||
c.second->SendAlternateAdvancementTable();
|
||||
c.second->SendAlternateAdvancementStats();
|
||||
c.second->SendAlternateAdvancementPoints();
|
||||
}
|
||||
}
|
||||
|
||||
@ -398,7 +398,6 @@ public:
|
||||
|
||||
void SaveAllClientsTaskState();
|
||||
void ReloadAllClientsTaskState(int TaskID=0);
|
||||
|
||||
uint16 CreateGroundObject(uint32 itemid, const glm::vec4& position, uint32 decay_time = 300000);
|
||||
uint16 CreateGroundObjectFromModel(const char *model, const glm::vec4& position, uint8 type = 0x00, uint32 decay_time = 0);
|
||||
uint16 CreateDoor(const char *model, const glm::vec4& position, uint8 type = 0, uint16 size = 100);
|
||||
@ -429,6 +428,7 @@ public:
|
||||
uint16 GetFreeID();
|
||||
void RefreshAutoXTargets(Client *c);
|
||||
void RefreshClientXTargets(Client *c);
|
||||
void SendAlternateAdvancementStats();
|
||||
|
||||
protected:
|
||||
friend class Zone;
|
||||
|
||||
@ -515,7 +515,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) {
|
||||
if (GetLevel() < 51) {
|
||||
m_epp.perAA = 0; // turn off aa exp if they drop below 51
|
||||
} 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
|
||||
uint32 tmpxp1 = GetEXPForLevel(GetLevel()+1);
|
||||
|
||||
@ -535,37 +535,20 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
|
||||
if (!target || !caster)
|
||||
return 0;
|
||||
|
||||
int ret = 0;
|
||||
std::list<uint32> id_list;
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
struct_HateList *h = (*iterator);
|
||||
++iterator;
|
||||
if (h && h->entity_on_hatelist && h->entity_on_hatelist != caster)
|
||||
{
|
||||
if (caster->CombatRange(h->entity_on_hatelist))
|
||||
{
|
||||
id_list.push_back(h->entity_on_hatelist->GetID());
|
||||
++ret;
|
||||
int hit_count = 0;
|
||||
auto it = list.begin();
|
||||
while (it != list.end() && hit_count < count) {
|
||||
struct_HateList *h = (*it);
|
||||
if (h && h->entity_on_hatelist && h->entity_on_hatelist != caster) {
|
||||
if (caster->CombatRange(h->entity_on_hatelist)) {
|
||||
++hit_count;
|
||||
caster->ProcessAttackRounds(h->entity_on_hatelist, opts);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
std::list<uint32>::iterator iter = id_list.begin();
|
||||
while (iter != id_list.end())
|
||||
{
|
||||
Mob *cur = entity_list.GetMobID((*iter));
|
||||
if (cur)
|
||||
{
|
||||
for (int i = 0; i < count; ++i) {
|
||||
caster->Attack(cur, MainPrimary, false, false, false, opts);
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return hit_count;
|
||||
}
|
||||
|
||||
void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_center)
|
||||
|
||||
@ -334,9 +334,11 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
|
||||
eslot = MaterialPrimary;
|
||||
if (item2->Damage > 0)
|
||||
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
||||
if (item2->ItemType == ItemType2HBlunt || item2->ItemType == ItemType2HSlash || item2->ItemType == ItemType2HPiercing)
|
||||
SetTwoHanderEquipped(true);
|
||||
}
|
||||
else if (foundslot == MainSecondary
|
||||
&& (GetOwner() != nullptr || (GetLevel() >= 13 && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) &&
|
||||
&& (GetOwner() != nullptr || (CanThisClassDualWield() && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) &&
|
||||
(item2->ItemType == ItemType1HSlash || item2->ItemType == ItemType1HBlunt || item2->ItemType == ItemTypeShield ||
|
||||
item2->ItemType == ItemType1HPiercing))
|
||||
{
|
||||
|
||||
@ -350,6 +350,11 @@ const char *Lua_Client::AccountName() {
|
||||
return self->AccountName();
|
||||
}
|
||||
|
||||
int Lua_Client::GetAccountAge() {
|
||||
Lua_Safe_Call_Int();
|
||||
return time(nullptr) - self->GetAccountCreation();
|
||||
}
|
||||
|
||||
int Lua_Client::Admin() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->Admin();
|
||||
@ -1024,7 +1029,17 @@ void Lua_Client::AddLevelBasedExp(int exp_pct, int max_level) {
|
||||
|
||||
void Lua_Client::IncrementAA(int aa) {
|
||||
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) {
|
||||
@ -1365,6 +1380,7 @@ luabind::scope lua_register_client() {
|
||||
.def("GetRawItemAC", (int(Lua_Client::*)(void))&Lua_Client::GetRawItemAC)
|
||||
.def("AccountID", (uint32(Lua_Client::*)(void))&Lua_Client::AccountID)
|
||||
.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("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID)
|
||||
.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,int))&Lua_Client::AddLevelBasedExp)
|
||||
.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,int))&Lua_Client::MarkSingleCompassLoc)
|
||||
.def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(void))&Lua_Client::GetNextAvailableSpellBookSlot)
|
||||
|
||||
@ -233,6 +233,8 @@ public:
|
||||
void AddLevelBasedExp(int exp_pct);
|
||||
void AddLevelBasedExp(int exp_pct, int max_level);
|
||||
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, int count);
|
||||
int GetNextAvailableSpellBookSlot();
|
||||
@ -260,6 +262,7 @@ public:
|
||||
bool HasSpellScribed(int spell_id);
|
||||
void SetAccountFlag(std::string flag, std::string val);
|
||||
std::string GetAccountFlag(std::string flag);
|
||||
int GetAccountAge();
|
||||
Lua_Group GetGroup();
|
||||
Lua_Raid GetRaid();
|
||||
bool PutItemInInventory(int slot_id, Lua_ItemInst inst);
|
||||
|
||||
@ -513,16 +513,16 @@ void lua_toggle_spawn_event(int event_id, bool enable, bool strict, bool reset)
|
||||
quest_manager.toggle_spawn_event(event_id, enable, strict, reset);
|
||||
}
|
||||
|
||||
void lua_summon_burried_player_corpse(uint32 char_id, float x, float y, float z, float h) {
|
||||
quest_manager.summonburriedplayercorpse(char_id, glm::vec4(x, y, z, h));
|
||||
void lua_summon_buried_player_corpse(uint32 char_id, float x, float y, float z, float h) {
|
||||
quest_manager.summonburiedplayercorpse(char_id, glm::vec4(x, y, z, h));
|
||||
}
|
||||
|
||||
void lua_summon_all_player_corpses(uint32 char_id, float x, float y, float z, float h) {
|
||||
quest_manager.summonallplayercorpses(char_id, glm::vec4(x, y, z, h));
|
||||
}
|
||||
|
||||
int lua_get_player_burried_corpse_count(uint32 char_id) {
|
||||
return quest_manager.getplayerburriedcorpsecount(char_id);
|
||||
int lua_get_player_buried_corpse_count(uint32 char_id) {
|
||||
return quest_manager.getplayerburiedcorpsecount(char_id);
|
||||
}
|
||||
|
||||
bool lua_bury_player_corpse(uint32 char_id) {
|
||||
@ -1524,9 +1524,9 @@ luabind::scope lua_register_general() {
|
||||
luabind::def("spawn_condition", &lua_spawn_condition),
|
||||
luabind::def("get_spawn_condition", &lua_get_spawn_condition),
|
||||
luabind::def("toggle_spawn_event", &lua_toggle_spawn_event),
|
||||
luabind::def("summon_burried_player_corpse", &lua_summon_burried_player_corpse),
|
||||
luabind::def("summon_buried_player_corpse", &lua_summon_buried_player_corpse),
|
||||
luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses),
|
||||
luabind::def("get_player_burried_corpse_count", &lua_get_player_burried_corpse_count),
|
||||
luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count),
|
||||
luabind::def("bury_player_corpse", &lua_bury_player_corpse),
|
||||
luabind::def("task_selector", &lua_task_selector),
|
||||
luabind::def("task_set_selector", &lua_task_set_selector),
|
||||
|
||||
@ -790,7 +790,7 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, in
|
||||
int16 res = resist_adjust;
|
||||
|
||||
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) {
|
||||
@ -1195,6 +1195,21 @@ int Lua_Mob::GetAA(int 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() {
|
||||
Lua_Safe_Call_Bool();
|
||||
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,uint32))&Lua_Mob::CheckHealAggroAmount)
|
||||
.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("SetOOCRegen", (void(Lua_Mob::*)(int))&Lua_Mob::SetOOCRegen)
|
||||
.def("GetEntityVariable", (const char*(Lua_Mob::*)(const char*))&Lua_Mob::GetEntityVariable)
|
||||
@ -2216,7 +2234,14 @@ luabind::scope lua_register_special_abilities() {
|
||||
luabind::value("destructible_object", static_cast<int>(DESTRUCTIBLE_OBJECT)),
|
||||
luabind::value("no_harm_from_client", static_cast<int>(NO_HARM_FROM_CLIENT)),
|
||||
luabind::value("always_flee", static_cast<int>(ALWAYS_FLEE)),
|
||||
luabind::value("flee_percent", static_cast<int>(FLEE_PERCENT))
|
||||
luabind::value("flee_percent", static_cast<int>(FLEE_PERCENT)),
|
||||
luabind::value("allow_beneficial", static_cast<int>(ALLOW_BENEFICIAL)),
|
||||
luabind::value("disable_melee", static_cast<int>(DISABLE_MELEE)),
|
||||
luabind::value("npc_chase_distance", static_cast<int>(NPC_CHASE_DISTANCE)),
|
||||
luabind::value("allow_to_tank", static_cast<int>(ALLOW_TO_TANK)),
|
||||
luabind::value("ignore_root_aggro_rules", static_cast<int>(IGNORE_ROOT_AGGRO_RULES)),
|
||||
luabind::value("casting_resist_diff", static_cast<int>(CASTING_RESIST_DIFF)),
|
||||
luabind::value("counter_avoid_damage", static_cast<int>(COUNTER_AVOID_DAMAGE))
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -249,6 +249,9 @@ public:
|
||||
int CheckHealAggroAmount(int spell_id);
|
||||
int CheckHealAggroAmount(int spell_id, uint32 heal_possible);
|
||||
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();
|
||||
void SetOOCRegen(int regen);
|
||||
const char* GetEntityVariable(const char *name);
|
||||
|
||||
47
zone/mob.cpp
47
zone/mob.cpp
@ -211,6 +211,7 @@ Mob::Mob(const char* in_name,
|
||||
trackable = true;
|
||||
has_shieldequiped = false;
|
||||
has_twohandbluntequiped = false;
|
||||
has_twohanderequipped = false;
|
||||
has_numhits = false;
|
||||
has_MGB = false;
|
||||
has_ProjectIllusion = false;
|
||||
@ -307,8 +308,8 @@ Mob::Mob(const char* in_name,
|
||||
casting_spell_id = 0;
|
||||
casting_spell_timer = 0;
|
||||
casting_spell_timer_duration = 0;
|
||||
casting_spell_type = 0;
|
||||
casting_spell_inventory_slot = 0;
|
||||
casting_spell_aa_id = 0;
|
||||
target = 0;
|
||||
|
||||
ActiveProjectileATK = false;
|
||||
@ -725,7 +726,7 @@ int Mob::_GetFearSpeed() const {
|
||||
movemod = -85;
|
||||
|
||||
if (IsClient()) {
|
||||
if (CastToClient()->IsRunning())
|
||||
if (CastToClient()->GetRunMode())
|
||||
speed_mod = GetBaseRunspeed();
|
||||
else
|
||||
speed_mod = GetBaseWalkspeed();
|
||||
@ -1085,7 +1086,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.max_hp = 100; //this field needs a better name
|
||||
ns->spawn.race = race;
|
||||
ns->spawn.runspeed = runspeed;
|
||||
ns->spawn.walkspeed = runspeed * 0.5f;
|
||||
ns->spawn.walkspeed = walkspeed;
|
||||
ns->spawn.class_ = class_;
|
||||
ns->spawn.gender = gender;
|
||||
ns->spawn.level = level;
|
||||
@ -1142,6 +1143,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
else
|
||||
ns->spawn.flymode = flymode;
|
||||
|
||||
if(IsBoat()) {
|
||||
ns->spawn.flymode = 1;
|
||||
}
|
||||
|
||||
ns->spawn.lastName[0] = '\0';
|
||||
|
||||
strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName));
|
||||
@ -1354,8 +1359,12 @@ void Mob::SendHPUpdate(bool skip_self)
|
||||
}
|
||||
}
|
||||
|
||||
bool dospam = RuleB(Character, SpamHPUpdates);
|
||||
// send to self - we need the actual hps here
|
||||
if(IsClient() && !skip_self) {
|
||||
if(IsClient() && (!skip_self || dospam)) {
|
||||
|
||||
this->CastToClient()->SendHPUpdateMarquee();
|
||||
|
||||
EQApplicationPacket* hp_app2 = new EQApplicationPacket(OP_HPUpdate,sizeof(SpawnHPUpdate_Struct));
|
||||
SpawnHPUpdate_Struct* ds = (SpawnHPUpdate_Struct*)hp_app2->pBuffer;
|
||||
ds->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
|
||||
@ -1364,6 +1373,7 @@ void Mob::SendHPUpdate(bool skip_self)
|
||||
CastToClient()->QueuePacket(hp_app2);
|
||||
safe_delete(hp_app2);
|
||||
}
|
||||
if (!dospam)
|
||||
ResetHPUpdateTimer(); // delay the timer
|
||||
}
|
||||
|
||||
@ -1385,8 +1395,9 @@ void Mob::SendPosUpdate(uint8 iSendToSelf) {
|
||||
MakeSpawnUpdate(spu);
|
||||
|
||||
if (iSendToSelf == 2) {
|
||||
if (this->IsClient())
|
||||
this->CastToClient()->FastQueuePacket(&app,false);
|
||||
if (IsClient()) {
|
||||
CastToClient()->FastQueuePacket(&app,false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1395,9 +1406,12 @@ void Mob::SendPosUpdate(uint8 iSendToSelf) {
|
||||
entity_list.QueueClients(this, app, (iSendToSelf == 0), false);
|
||||
move_tic_count = 0;
|
||||
}
|
||||
else
|
||||
else if(move_tic_count % 2 == 0)
|
||||
{
|
||||
entity_list.QueueCloseClients(this, app, (iSendToSelf==0), 800, nullptr, false);
|
||||
entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), 700, nullptr, false);
|
||||
move_tic_count++;
|
||||
}
|
||||
else {
|
||||
move_tic_count++;
|
||||
}
|
||||
}
|
||||
@ -1475,7 +1489,7 @@ void Mob::ShowStats(Client* client)
|
||||
if(n->respawn2 != 0)
|
||||
spawngroupid = n->respawn2->SpawnGroupID();
|
||||
client->Message(0, " NPCID: %u SpawnGroupID: %u Grid: %i LootTable: %u FactionID: %i SpellsID: %u ", GetNPCTypeID(),spawngroupid, n->GetGrid(), n->GetLoottableID(), n->GetNPCFactionID(), n->GetNPCSpellsID());
|
||||
client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %u Walkspeed: %u", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed());
|
||||
client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %.3f Walkspeed: %.3f", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), static_cast<float>(0.025f * n->GetRunspeed()), static_cast<float>(0.025f * n->GetWalkspeed()));
|
||||
n->QueryLoot(client);
|
||||
}
|
||||
if (IsAIControlled()) {
|
||||
@ -2399,6 +2413,14 @@ bool Mob::CanThisClassDoubleAttack(void) const
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::CanThisClassTripleAttack() const
|
||||
{
|
||||
if (!IsClient())
|
||||
return false; // When they added the real triple attack skill, mobs lost the ability to triple
|
||||
else
|
||||
return CastToClient()->HasSkill(SkillTripleAttack);
|
||||
}
|
||||
|
||||
bool Mob::IsWarriorClass(void) const
|
||||
{
|
||||
switch(GetClass())
|
||||
@ -3507,7 +3529,9 @@ void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger)
|
||||
|
||||
if (aa_trigger && IsClient()) {
|
||||
// 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())
|
||||
SpellFinished(trigger_spell_id, GetTarget(), 10, 0, -1, spells[trigger_spell_id].ResistDiff);
|
||||
@ -3763,11 +3787,8 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
|
||||
skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] +
|
||||
itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used];
|
||||
|
||||
|
||||
skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1];
|
||||
|
||||
skilldmg_mod += spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability;
|
||||
|
||||
if(skilldmg_mod < -100)
|
||||
skilldmg_mod = -100;
|
||||
|
||||
|
||||
49
zone/mob.h
49
zone/mob.h
@ -23,6 +23,8 @@
|
||||
#include "hate_list.h"
|
||||
#include "pathing.h"
|
||||
#include "position.h"
|
||||
#include "aa_ability.h"
|
||||
#include "aa.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@ -147,7 +149,7 @@ public:
|
||||
int MonkSpecialAttack(Mob* other, uint8 skill_used);
|
||||
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
|
||||
void TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary, int damage = 0);
|
||||
virtual bool AvoidDamage(Mob* attacker, int32 &damage, bool CanRiposte = true);
|
||||
bool AvoidDamage(Mob* attacker, int32 &damage, int hand);
|
||||
virtual bool CheckHitChance(Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod = 0);
|
||||
virtual void TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts = nullptr);
|
||||
void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage);
|
||||
@ -164,6 +166,20 @@ public:
|
||||
void CommonOutgoingHitSuccess(Mob* defender, int32 &damage, SkillUseTypes skillInUse);
|
||||
void CommonBreakInvisible();
|
||||
bool HasDied();
|
||||
virtual bool CheckDualWield();
|
||||
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
||||
void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool CheckDoubleAttack();
|
||||
// inline process for places where we need to do them outside of the AI_Process
|
||||
void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr)
|
||||
{
|
||||
if (target) {
|
||||
DoMainHandAttackRounds(target, opts);
|
||||
if (CanThisClassDualWield())
|
||||
DoOffHandAttackRounds(target, opts);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//Appearance
|
||||
void SendLevelAppearance();
|
||||
@ -221,10 +237,12 @@ public:
|
||||
virtual void SpellProcess();
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
||||
bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0,
|
||||
@ -318,6 +336,8 @@ public:
|
||||
inline void SetShieldEquiped(bool val) { has_shieldequiped = val; }
|
||||
bool HasTwoHandBluntEquiped() const { return has_twohandbluntequiped; }
|
||||
inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; }
|
||||
bool HasTwoHanderEquipped() { return has_twohanderequipped; }
|
||||
void SetTwoHanderEquipped(bool val) { has_twohanderequipped = val; }
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; }
|
||||
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
||||
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
@ -365,7 +385,7 @@ public:
|
||||
inline Mob* GetTarget() const { return target; }
|
||||
virtual void SetTarget(Mob* mob);
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
|
||||
virtual inline float GetIntHPRatio() const { return max_hp == 0 ? 0 : (cur_hp/max_hp*100); }
|
||||
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp); }
|
||||
inline virtual int32 GetAC() const { return AC + itembonuses.AC + spellbonuses.AC; }
|
||||
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
|
||||
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
@ -730,6 +750,7 @@ public:
|
||||
virtual int GetMonkHandToHandDamage(void);
|
||||
|
||||
bool CanThisClassDoubleAttack(void) const;
|
||||
bool CanThisClassTripleAttack() const;
|
||||
bool CanThisClassDualWield(void) const;
|
||||
bool CanThisClassRiposte(void) const;
|
||||
bool CanThisClassDodge(void) const;
|
||||
@ -860,7 +881,6 @@ public:
|
||||
uint32 GetZoneID() const; //for perl
|
||||
virtual int32 CheckAggroAmount(uint16 spell_id, bool isproc = false);
|
||||
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;
|
||||
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0);
|
||||
@ -956,6 +976,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_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:
|
||||
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);
|
||||
@ -969,7 +1002,6 @@ protected:
|
||||
virtual bool AI_PursueCastCheck() { return(false); }
|
||||
virtual bool AI_IdleCastCheck() { return(false); }
|
||||
|
||||
|
||||
bool IsFullHP;
|
||||
bool moved;
|
||||
|
||||
@ -1145,6 +1177,7 @@ protected:
|
||||
uint32 casting_spell_timer_duration;
|
||||
uint32 casting_spell_type;
|
||||
int16 casting_spell_resist_adjust;
|
||||
uint32 casting_spell_aa_id;
|
||||
bool casting_spell_checks;
|
||||
uint16 bardsong;
|
||||
uint8 bardsong_slot;
|
||||
@ -1191,6 +1224,7 @@ protected:
|
||||
bool offhand;
|
||||
bool has_shieldequiped;
|
||||
bool has_twohandbluntequiped;
|
||||
bool has_twohanderequipped;
|
||||
bool has_numhits;
|
||||
bool has_MGB;
|
||||
bool has_ProjectIllusion;
|
||||
@ -1311,6 +1345,9 @@ protected:
|
||||
bool bEnraged;
|
||||
bool destructibleobject;
|
||||
|
||||
std::unordered_map<uint32, std::pair<uint32, uint32>> aa_ranks;
|
||||
Timer aa_timers[aaTimerMax];
|
||||
|
||||
private:
|
||||
void _StopSong(); //this is not what you think it is
|
||||
Mob* target;
|
||||
|
||||
200
zone/mob_ai.cpp
200
zone/mob_ai.cpp
@ -342,7 +342,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
|
||||
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) {
|
||||
@ -772,7 +772,10 @@ void Client::AI_Process()
|
||||
engaged = true;
|
||||
} else {
|
||||
if(AImovement_timer->Check()) {
|
||||
//animation = GetFearSpeed() * 21;
|
||||
int speed = GetFearSpeed();
|
||||
animation = speed;
|
||||
speed *= 2;
|
||||
SetCurrentSpeed(speed);
|
||||
// Check if we have reached the last fear point
|
||||
if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) &&
|
||||
(std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) {
|
||||
@ -780,18 +783,18 @@ void Client::AI_Process()
|
||||
CalculateNewFearpoint();
|
||||
}
|
||||
if(!RuleB(Pathing, Fear) || !zone->pathing)
|
||||
CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true);
|
||||
CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed, true);
|
||||
else
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
|
||||
glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z,
|
||||
GetFearSpeed(), WaypointChanged, NodeReached);
|
||||
speed, WaypointChanged, NodeReached);
|
||||
|
||||
if(WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetFearSpeed());
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -830,8 +833,8 @@ void Client::AI_Process()
|
||||
}
|
||||
|
||||
if (AImovement_timer->Check()) {
|
||||
if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w)
|
||||
{
|
||||
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) !=
|
||||
m_Position.w) {
|
||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
||||
SendPosition();
|
||||
}
|
||||
@ -839,103 +842,30 @@ void Client::AI_Process()
|
||||
}
|
||||
if (GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) {
|
||||
if (attack_timer.Check()) {
|
||||
Attack(GetTarget(), MainPrimary);
|
||||
if(GetTarget()) {
|
||||
if(CheckDoubleAttack()) {
|
||||
Attack(GetTarget(), MainPrimary);
|
||||
if(GetTarget()) {
|
||||
bool triple_attack_success = false;
|
||||
if((((GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER)
|
||||
&& GetLevel() >= 60) || GetSpecialAbility(SPECATK_TRIPLE))
|
||||
&& CheckDoubleAttack(true))
|
||||
{
|
||||
Attack(GetTarget(), MainPrimary, true);
|
||||
triple_attack_success = true;
|
||||
}
|
||||
|
||||
if(GetTarget())
|
||||
{
|
||||
//Live AA - Flurry, Rapid Strikes ect (Flurry does not require Triple Attack).
|
||||
int16 flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance;
|
||||
|
||||
if (flurrychance)
|
||||
{
|
||||
if(zone->random.Roll(flurrychance))
|
||||
{
|
||||
Message_StringID(MT_NPCFlurry, YOU_FLURRY);
|
||||
Attack(GetTarget(), MainPrimary, false);
|
||||
Attack(GetTarget(), MainPrimary, false);
|
||||
// Should charmed clients not be procing?
|
||||
DoAttackRounds(GetTarget(), MainPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
int16 ExtraAttackChanceBonus = spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance;
|
||||
|
||||
if (ExtraAttackChanceBonus && GetTarget()) {
|
||||
ItemInst *wpn = GetInv().GetItem(MainPrimary);
|
||||
if(wpn){
|
||||
if(wpn->GetItem()->ItemType == ItemType2HSlash ||
|
||||
wpn->GetItem()->ItemType == ItemType2HBlunt ||
|
||||
wpn->GetItem()->ItemType == ItemType2HPiercing )
|
||||
{
|
||||
if(zone->random.Roll(ExtraAttackChanceBonus))
|
||||
{
|
||||
Attack(GetTarget(), MainPrimary, false);
|
||||
if (CanThisClassDualWield() && GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) {
|
||||
if (attack_dw_timer.Check()) {
|
||||
if (CheckDualWield()) {
|
||||
// Should charmed clients not be procing?
|
||||
DoAttackRounds(GetTarget(), MainSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GetClass() == WARRIOR || GetClass() == BERSERKER)
|
||||
{
|
||||
if(!dead && !berserk && this->GetHPRatio() < 30)
|
||||
{
|
||||
entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_START, GetName());
|
||||
berserk = true;
|
||||
}
|
||||
else if (berserk && this->GetHPRatio() > 30)
|
||||
{
|
||||
entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_END, GetName());
|
||||
berserk = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(CanThisClassDualWield() && attack_dw_timer.Check())
|
||||
{
|
||||
if(GetTarget())
|
||||
{
|
||||
float DualWieldProbability = 0.0f;
|
||||
|
||||
int16 Ambidexterity = aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity;
|
||||
DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max
|
||||
int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance;
|
||||
DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f;
|
||||
|
||||
if(zone->random.Roll(DualWieldProbability))
|
||||
{
|
||||
Attack(GetTarget(), MainSecondary);
|
||||
if(CheckDoubleAttack())
|
||||
{
|
||||
Attack(GetTarget(), MainSecondary);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if(!IsRooted())
|
||||
{
|
||||
if(AImovement_timer->Check())
|
||||
{
|
||||
int newspeed = GetRunspeed();
|
||||
animation = newspeed;
|
||||
newspeed *= 2;
|
||||
SetCurrentSpeed(newspeed);
|
||||
if(!RuleB(Pathing, Aggro) || !zone->pathing)
|
||||
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
|
||||
CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), newspeed);
|
||||
else
|
||||
{
|
||||
bool WaypointChanged, NodeReached;
|
||||
@ -945,7 +875,7 @@ void Client::AI_Process()
|
||||
if(WaypointChanged)
|
||||
tar_ndx = 20;
|
||||
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed());
|
||||
CalculateNewPosition2(Goal.x, Goal.y, Goal.z, newspeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -989,11 +919,12 @@ void Client::AI_Process()
|
||||
{
|
||||
if(AImovement_timer->Check())
|
||||
{
|
||||
int speed = GetWalkspeed();
|
||||
if (dist >= 5625)
|
||||
speed = GetRunspeed();
|
||||
int nspeed = (dist >= 5625 ? GetRunspeed() : GetWalkspeed());
|
||||
animation = nspeed;
|
||||
nspeed *= 2;
|
||||
SetCurrentSpeed(nspeed);
|
||||
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1170,43 +1101,9 @@ void Mob::AI_Process() {
|
||||
|
||||
//try main hand first
|
||||
if(attack_timer.Check()) {
|
||||
if(IsNPC()) {
|
||||
int16 n_atk = CastToNPC()->GetNumberOfAttacks();
|
||||
if(n_atk <= 1) {
|
||||
Attack(target, MainPrimary);
|
||||
} else {
|
||||
for(int i = 0; i < n_atk; ++i) {
|
||||
Attack(target, MainPrimary);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Attack(target, MainPrimary);
|
||||
}
|
||||
|
||||
if (target) {
|
||||
//we use this random value in three comparisons with different
|
||||
//thresholds, and if its truely random, then this should work
|
||||
//out reasonably and will save us compute resources.
|
||||
int32 RandRoll = zone->random.Int(0, 99);
|
||||
if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE)
|
||||
|| GetSpecialAbility(SPECATK_QUAD))
|
||||
//check double attack, this is NOT the same rules that clients use...
|
||||
&& RandRoll < (GetLevel() + NPCDualAttackModifier)) {
|
||||
Attack(target, MainPrimary);
|
||||
// lets see if we can do a triple attack with the main hand
|
||||
//pets are excluded from triple and quads...
|
||||
if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD))
|
||||
&& !IsPet() && RandRoll < (GetLevel() + NPCTripleAttackModifier)) {
|
||||
Attack(target, MainPrimary);
|
||||
// now lets check the quad attack
|
||||
if (GetSpecialAbility(SPECATK_QUAD)
|
||||
&& RandRoll < (GetLevel() + NPCQuadAttackModifier)) {
|
||||
Attack(target, MainPrimary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DoMainHandAttackRounds(target);
|
||||
|
||||
bool specialed = false; // NPCs can only do one of these a round
|
||||
if (GetSpecialAbility(SPECATK_FLURRY)) {
|
||||
int flurry_chance = GetSpecialAbilityParam(SPECATK_FLURRY, 0);
|
||||
flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance);
|
||||
@ -1238,6 +1135,7 @@ void Mob::AI_Process() {
|
||||
opts.crit_flat = cur;
|
||||
|
||||
Flurry(&opts);
|
||||
specialed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1258,7 +1156,7 @@ void Mob::AI_Process() {
|
||||
}
|
||||
}
|
||||
|
||||
if (GetSpecialAbility(SPECATK_RAMPAGE))
|
||||
if (GetSpecialAbility(SPECATK_RAMPAGE) && !specialed)
|
||||
{
|
||||
int rampage_chance = GetSpecialAbilityParam(SPECATK_RAMPAGE, 0);
|
||||
rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
|
||||
@ -1294,10 +1192,11 @@ void Mob::AI_Process() {
|
||||
opts.crit_flat = cur;
|
||||
}
|
||||
Rampage(&opts);
|
||||
specialed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetSpecialAbility(SPECATK_AREA_RAMPAGE))
|
||||
if (GetSpecialAbility(SPECATK_AREA_RAMPAGE) && !specialed)
|
||||
{
|
||||
int rampage_chance = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 0);
|
||||
rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
|
||||
@ -1334,30 +1233,14 @@ void Mob::AI_Process() {
|
||||
}
|
||||
|
||||
AreaRampage(&opts);
|
||||
specialed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//now off hand
|
||||
if (attack_dw_timer.Check() && CanThisClassDualWield())
|
||||
{
|
||||
int myclass = GetClass();
|
||||
//can only dual wield without a weapon if your a monk
|
||||
if(GetSpecialAbility(SPECATK_INNATE_DW) || (GetEquipment(MaterialSecondary) != 0 && GetLevel() > 29) || myclass == MONK || myclass == MONKGM) {
|
||||
float DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel()) / 400.0f;
|
||||
if(zone->random.Roll(DualWieldProbability))
|
||||
{
|
||||
Attack(target, MainSecondary);
|
||||
if (CanThisClassDoubleAttack())
|
||||
{
|
||||
if (zone->random.Roll(GetLevel() + 20))
|
||||
{
|
||||
Attack(target, MainSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DoOffHandAttackRounds(target);
|
||||
|
||||
//now special attacks (kick, etc)
|
||||
if(IsNPC())
|
||||
@ -2095,14 +1978,14 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
|
||||
if (m_target == GetTarget())
|
||||
continue;
|
||||
if (CombatRange(m_target)) {
|
||||
Attack(m_target, MainPrimary, false, false, false, opts);
|
||||
ProcessAttackRounds(m_target, opts);
|
||||
index_hit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets)
|
||||
Attack(GetTarget(), MainPrimary, false, false, false, opts);
|
||||
ProcessAttackRounds(GetTarget(), opts);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2120,9 +2003,8 @@ void Mob::AreaRampage(ExtraAttackOptions *opts)
|
||||
rampage_targets = rampage_targets > 0 ? rampage_targets : 1;
|
||||
index_hit = hate_list.AreaRampage(this, GetTarget(), rampage_targets, opts);
|
||||
|
||||
if(index_hit == 0) {
|
||||
Attack(GetTarget(), MainPrimary, false, false, false, opts);
|
||||
}
|
||||
if(index_hit == 0)
|
||||
ProcessAttackRounds(GetTarget(), opts);
|
||||
}
|
||||
|
||||
uint32 Mob::GetLevelCon(uint8 mylevel, uint8 iOtherLevel) {
|
||||
|
||||
106
zone/net.cpp
106
zone/net.cpp
@ -28,7 +28,6 @@
|
||||
#include "../common/eq_packet_structs.h"
|
||||
#include "../common/mutex.h"
|
||||
#include "../common/version.h"
|
||||
|
||||
#include "../common/packet_dump_file.h"
|
||||
#include "../common/opcodemgr.h"
|
||||
#include "../common/guilds.h"
|
||||
@ -57,17 +56,14 @@
|
||||
#include "titles.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "tasks.h"
|
||||
|
||||
#include "quest_parser_collection.h"
|
||||
#include "embparser.h"
|
||||
#include "lua_parser.h"
|
||||
|
||||
#include "questmgr.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@ -96,7 +92,6 @@ EntityList entity_list;
|
||||
WorldServer worldserver;
|
||||
uint32 numclients = 0;
|
||||
char errorname[32];
|
||||
uint16 adverrornum = 0;
|
||||
extern Zone* zone;
|
||||
EQStreamFactory eqsf(ZoneStream);
|
||||
npcDecayTimes_Struct npcCorpseDecayTimes[100];
|
||||
@ -116,35 +111,8 @@ int main(int argc, char** argv) {
|
||||
RegisterExecutablePlatform(ExePlatformZone);
|
||||
Log.LoadLogSettingsDefaults();
|
||||
set_exception_handler();
|
||||
const char *zone_name;
|
||||
QServ = new QueryServ;
|
||||
|
||||
if(argc == 3) {
|
||||
worldserver.SetLauncherName(argv[2]);
|
||||
worldserver.SetLaunchedName(argv[1]);
|
||||
if(strncmp(argv[1], "dynamic_", 8) == 0) {
|
||||
//dynamic zone with a launcher name correlation
|
||||
zone_name = ".";
|
||||
} else {
|
||||
zone_name = argv[1];
|
||||
worldserver.SetLaunchedName(zone_name);
|
||||
}
|
||||
} else if (argc == 2) {
|
||||
worldserver.SetLauncherName("NONE");
|
||||
worldserver.SetLaunchedName(argv[1]);
|
||||
if(strncmp(argv[1], "dynamic_", 8) == 0) {
|
||||
//dynamic zone with a launcher name correlation
|
||||
zone_name = ".";
|
||||
} else {
|
||||
zone_name = argv[1];
|
||||
worldserver.SetLaunchedName(zone_name);
|
||||
}
|
||||
} else {
|
||||
zone_name = ".";
|
||||
worldserver.SetLaunchedName(".");
|
||||
worldserver.SetLauncherName("NONE");
|
||||
}
|
||||
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Loading server configuration..");
|
||||
if(!ZoneConfig::LoadConfig()) {
|
||||
Log.Out(Logs::General, Logs::Error, "Loading server configuration failed.");
|
||||
@ -152,6 +120,75 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
const ZoneConfig *Config = ZoneConfig::get();
|
||||
|
||||
const char *zone_name;
|
||||
uint32 instance_id = 0;
|
||||
std::string z_name;
|
||||
if(argc == 4) {
|
||||
instance_id = atoi(argv[3]);
|
||||
worldserver.SetLauncherName(argv[2]);
|
||||
auto zone_port = SplitString(argv[1], ':');
|
||||
|
||||
if(zone_port.size() > 0) {
|
||||
z_name = zone_port[0];
|
||||
}
|
||||
|
||||
if(zone_port.size() > 1) {
|
||||
std::string p_name = zone_port[1];
|
||||
Config->SetZonePort(atoi(p_name.c_str()));
|
||||
}
|
||||
|
||||
worldserver.SetLaunchedName(z_name.c_str());
|
||||
if(strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
||||
zone_name = ".";
|
||||
}
|
||||
else {
|
||||
zone_name = z_name.c_str();
|
||||
}
|
||||
} else if(argc == 3) {
|
||||
worldserver.SetLauncherName(argv[2]);
|
||||
auto zone_port = SplitString(argv[1], ':');
|
||||
|
||||
if(zone_port.size() > 0) {
|
||||
z_name = zone_port[0];
|
||||
}
|
||||
|
||||
if(zone_port.size() > 1) {
|
||||
std::string p_name = zone_port[1];
|
||||
Config->SetZonePort(atoi(p_name.c_str()));
|
||||
}
|
||||
|
||||
worldserver.SetLaunchedName(z_name.c_str());
|
||||
if(strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
||||
zone_name = ".";
|
||||
} else {
|
||||
zone_name = z_name.c_str();
|
||||
}
|
||||
} else if (argc == 2) {
|
||||
worldserver.SetLauncherName("NONE");
|
||||
auto zone_port = SplitString(argv[1], ':');
|
||||
|
||||
if(zone_port.size() > 0) {
|
||||
z_name = zone_port[0];
|
||||
}
|
||||
|
||||
if(zone_port.size() > 1) {
|
||||
std::string p_name = zone_port[1];
|
||||
Config->SetZonePort(atoi(p_name.c_str()));
|
||||
}
|
||||
|
||||
worldserver.SetLaunchedName(z_name.c_str());
|
||||
if(strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
||||
zone_name = ".";
|
||||
}
|
||||
else {
|
||||
zone_name = z_name.c_str();
|
||||
}
|
||||
} else {
|
||||
zone_name = ".";
|
||||
worldserver.SetLaunchedName(".");
|
||||
worldserver.SetLauncherName("NONE");
|
||||
}
|
||||
|
||||
worldserver.SetPassword(Config->SharedKey.c_str());
|
||||
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Connecting to MySQL...");
|
||||
@ -257,9 +294,6 @@ int main(int argc, char** argv) {
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Loading titles");
|
||||
title_manager.LoadTitles();
|
||||
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Loading AA effects");
|
||||
database.LoadAAEffects();
|
||||
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Loading tributes");
|
||||
database.LoadTributes();
|
||||
|
||||
@ -324,7 +358,7 @@ int main(int argc, char** argv) {
|
||||
#endif
|
||||
if (!strlen(zone_name) || !strcmp(zone_name,".")) {
|
||||
Log.Out(Logs::General, Logs::Zone_Server, "Entering sleep mode");
|
||||
} else if (!Zone::Bootup(database.GetZoneID(zone_name), 0, true)) { //todo: go above and fix this to allow cmd line instance
|
||||
} else if (!Zone::Bootup(database.GetZoneID(zone_name), instance_id, true)) {
|
||||
Log.Out(Logs::General, Logs::Error, "Zone Bootup failed :: Zone::Bootup");
|
||||
zone = 0;
|
||||
}
|
||||
|
||||
23
zone/npc.cpp
23
zone/npc.cpp
@ -31,7 +31,6 @@
|
||||
#include "../common/linked_list.h"
|
||||
#include "../common/servertalk.h"
|
||||
|
||||
#include "aa.h"
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
#include "npc.h"
|
||||
@ -279,6 +278,18 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
for(r = 0; r <= HIGHEST_SKILL; r++) {
|
||||
skills[r] = database.GetSkillCap(GetClass(),(SkillUseTypes)r,moblevel);
|
||||
}
|
||||
// some overrides -- really we need to be able to set skills for mobs in the DB
|
||||
// There are some known low level SHM/BST pets that do not follow this, which supports
|
||||
// the theory of needing to be able to set skills for each mob separately
|
||||
if (moblevel > 50) {
|
||||
skills[SkillDoubleAttack] = 250;
|
||||
skills[SkillDualWield] = 250;
|
||||
} else if (moblevel > 3) {
|
||||
skills[SkillDoubleAttack] = moblevel * 5;
|
||||
skills[SkillDualWield] = skills[SkillDoubleAttack];
|
||||
} else {
|
||||
skills[SkillDoubleAttack] = moblevel * 5;
|
||||
}
|
||||
|
||||
if(d->trap_template > 0)
|
||||
{
|
||||
@ -1929,7 +1940,15 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
else if(id == "pr") { PR = atoi(val.c_str()); return; }
|
||||
else if(id == "dr") { DR = atoi(val.c_str()); return; }
|
||||
else if(id == "PhR") { PhR = atoi(val.c_str()); return; }
|
||||
else if(id == "runspeed") { runspeed = (float)atof(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "runspeed") {
|
||||
runspeed = (float)atof(val.c_str());
|
||||
base_runspeed = (int)((float)runspeed * 40.0f);
|
||||
base_walkspeed = base_runspeed * 100 / 265;
|
||||
walkspeed = ((float)base_walkspeed) * 0.025f;
|
||||
base_fearspeed = base_runspeed * 100 / 127;
|
||||
fearspeed = ((float)base_fearspeed) * 0.025f;
|
||||
CalcBonuses(); return;
|
||||
}
|
||||
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; }
|
||||
else if(id == "special_abilities") { ProcessSpecialAbilities(val.c_str()); return; }
|
||||
else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; }
|
||||
|
||||
@ -4077,33 +4077,7 @@ XS(XS_Client_RefundAA) {
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
int curpt = 0;
|
||||
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
|
||||
}
|
||||
THIS->RefundAA();
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@ -4915,11 +4889,44 @@ XS(XS_Client_IncrementAA)
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
THIS->IncrementAA(aaskillid);
|
||||
THIS->IncrementAlternateAdvancementRank(aaskillid);
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -6463,6 +6470,7 @@ XS(boot_Client)
|
||||
newXSproto(strcpy(buf, "GetIP"), XS_Client_GetIP, file, "$");
|
||||
newXSproto(strcpy(buf, "AddLevelBasedExp"), XS_Client_AddLevelBasedExp, 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, "MarkCompassLoc"), XS_Client_MarkCompassLoc, file, "$$$$");
|
||||
newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, 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
|
||||
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
|
||||
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;
|
||||
}
|
||||
@ -6360,7 +6360,34 @@ XS(XS_Mob_GetAA)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetAA(THIS, aa_id)");
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetAA(THIS, rank_id)");
|
||||
{
|
||||
Mob * THIS;
|
||||
uint32 RETVAL;
|
||||
dXSTARG;
|
||||
uint32 rank_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->GetAA(rank_id);
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
}
|
||||
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;
|
||||
@ -6376,12 +6403,41 @@ XS(XS_Mob_GetAA)
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetAA(aa_id);
|
||||
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)
|
||||
{
|
||||
@ -8625,6 +8681,8 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "CheckAggroAmount"), XS_Mob_CheckAggroAmount, file, "$$");
|
||||
newXSproto(strcpy(buf, "CheckHealAggroAmount"), XS_Mob_CheckHealAggroAmount, 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, "AddFeignMemory"), XS_Mob_AddFeignMemory, file, "$$");
|
||||
newXSproto(strcpy(buf, "RemoveFromFeignMemory"), XS_Mob_RemoveFromFeignMemory, file, "$$");
|
||||
|
||||
@ -874,7 +874,7 @@ bool QuestManager::isdisctome(int item_id) {
|
||||
void QuestManager::safemove() {
|
||||
QuestManagerCurrentQuestVars();
|
||||
if (initiator && initiator->IsClient())
|
||||
initiator->GoToSafeCoords(zone->GetZoneID(), 0);
|
||||
initiator->GoToSafeCoords(zone->GetZoneID(), zone->GetInstanceID());
|
||||
}
|
||||
|
||||
void QuestManager::rain(int weather) {
|
||||
@ -1774,7 +1774,7 @@ void QuestManager::sethp(int hpperc) {
|
||||
owner->Damage(owner, newhp, SPELL_UNKNOWN, SkillHandtoHand, false, 0, false);
|
||||
}
|
||||
|
||||
bool QuestManager::summonburriedplayercorpse(uint32 char_id, const glm::vec4& position) {
|
||||
bool QuestManager::summonburiedplayercorpse(uint32 char_id, const glm::vec4& position) {
|
||||
bool Result = false;
|
||||
|
||||
if(char_id <= 0)
|
||||
@ -1798,7 +1798,7 @@ bool QuestManager::summonallplayercorpses(uint32 char_id, const glm::vec4& posit
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 QuestManager::getplayerburriedcorpsecount(uint32 char_id) {
|
||||
uint32 QuestManager::getplayerburiedcorpsecount(uint32 char_id) {
|
||||
uint32 Result = 0;
|
||||
|
||||
if(char_id > 0) {
|
||||
|
||||
@ -159,9 +159,9 @@ public:
|
||||
void set_zone_flag(int zone_id);
|
||||
void clear_zone_flag(int zone_id);
|
||||
void sethp(int hpperc);
|
||||
bool summonburriedplayercorpse(uint32 char_id, const glm::vec4& position);
|
||||
bool summonburiedplayercorpse(uint32 char_id, const glm::vec4& position);
|
||||
bool summonallplayercorpses(uint32 char_id, const glm::vec4& position);
|
||||
uint32 getplayerburriedcorpsecount(uint32 char_id);
|
||||
uint32 getplayerburiedcorpsecount(uint32 char_id);
|
||||
bool buryplayercorpse(uint32 char_id);
|
||||
void forcedooropen(uint32 doorid, bool altmode);
|
||||
void forcedoorclose(uint32 doorid, bool altmode);
|
||||
|
||||
@ -130,49 +130,41 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
||||
|
||||
min_damage += min_damage * GetMeleeMinDamageMod_SE(skill) / 100;
|
||||
|
||||
if(HitChance && !who->CheckHitChance(this, skill, MainPrimary))
|
||||
max_damage = 0;
|
||||
|
||||
else{
|
||||
bool CanRiposte = true;
|
||||
if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&'
|
||||
CanRiposte = false;
|
||||
|
||||
if (CanAvoid)
|
||||
who->AvoidDamage(this, max_damage, CanRiposte);
|
||||
|
||||
int hand = MainPrimary; // Avoid checks hand for throwing/archery exclusion, primary should work for most
|
||||
if (skill == SkillThrowing || skill == SkillArchery)
|
||||
hand = MainRange;
|
||||
if (who->AvoidDamage(this, max_damage, hand)) {
|
||||
if (max_damage == -3)
|
||||
DoRiposte(who);
|
||||
} else {
|
||||
if (HitChance || who->CheckHitChance(this, skill, MainPrimary)) {
|
||||
who->MeleeMitigation(this, max_damage, min_damage);
|
||||
|
||||
if(max_damage > 0)
|
||||
CommonOutgoingHitSuccess(who, max_damage, skill);
|
||||
|
||||
} else {
|
||||
max_damage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//Make sure 'this' has not killed the target and 'this' is not dead (Damage shield ect).
|
||||
if(!GetTarget())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())
|
||||
TrySkillProc(who, skill, ReuseTime*1000);
|
||||
|
||||
if (max_damage > 0 && HasSkillProcSuccess())
|
||||
TrySkillProc(who, skill, ReuseTime*1000, true);
|
||||
|
||||
if(max_damage == -3 && !who->HasDied())
|
||||
DoRiposte(who);
|
||||
}
|
||||
|
||||
|
||||
@ -544,7 +536,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
|
||||
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
if (level > 54) {
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack())
|
||||
{
|
||||
if(other->GetHP() > 0)
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
@ -566,7 +558,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
|
||||
if (level > 54) {
|
||||
|
||||
// Check for double attack with main hand assuming maxed DA Skill (MS)
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack())
|
||||
if(other->GetHP() > 0)
|
||||
RogueBackstab(other,true, ReuseTime);
|
||||
|
||||
@ -975,7 +967,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
}
|
||||
|
||||
if (!HeadShot)
|
||||
other->AvoidDamage(this, TotalDmg, false);
|
||||
other->AvoidDamage(this, TotalDmg, MainRange);
|
||||
|
||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||
if(TotalDmg > 0){
|
||||
@ -1308,7 +1300,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
||||
|
||||
TotalDmg += TotalDmg * damage_mod / 100;
|
||||
|
||||
other->AvoidDamage(this, TotalDmg, false);
|
||||
other->AvoidDamage(this, TotalDmg, MainRange);
|
||||
other->MeleeMitigation(this, TotalDmg, MinDmg);
|
||||
|
||||
if (TotalDmg > 0)
|
||||
@ -1542,7 +1534,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg);
|
||||
if (!Assassinate_Dmg)
|
||||
other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks.
|
||||
other->AvoidDamage(this, TotalDmg, MainRange);
|
||||
|
||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||
if(TotalDmg > 0)
|
||||
@ -2414,27 +2406,26 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
else
|
||||
damage = zone->random.Int(min_hit, max_hit);
|
||||
|
||||
if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod)) {
|
||||
damage = 0;
|
||||
} else {
|
||||
other->AvoidDamage(this, damage, CanRiposte);
|
||||
other->MeleeMitigation(this, damage, min_hit);
|
||||
if(damage > 0)
|
||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||
}
|
||||
|
||||
if (other->AvoidDamage(this, damage, CanRiposte ? MainRange : MainPrimary)) { // MainRange excludes ripo, primary doesn't have any extra behavior
|
||||
if (damage == -3) {
|
||||
DoRiposte(other);
|
||||
if (HasDied())
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (other->CheckHitChance(this, skillinuse, Hand, chance_mod)) {
|
||||
other->MeleeMitigation(this, damage, min_hit);
|
||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||
} else {
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
damage = -5;
|
||||
|
||||
other->AddToHateList(this, hate);
|
||||
|
||||
bool CanSkillProc = true;
|
||||
if (skillinuse == SkillOffense){ //Hack to allow damage to display.
|
||||
skillinuse = SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message.
|
||||
@ -2442,19 +2433,18 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (HasDied())
|
||||
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())
|
||||
TrySkillProc(other, skillinuse, ReuseTime);
|
||||
|
||||
|
||||
@ -638,41 +638,23 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
snprintf(effect_desc, _EDLEN, "Group Fear Immunity");
|
||||
#endif
|
||||
//Added client messages to give some indication this effect is active.
|
||||
uint32 group_id_caster = 0;
|
||||
uint32 time = spell.base[i]*10;
|
||||
if(caster->IsClient())
|
||||
{
|
||||
if(caster->IsGrouped())
|
||||
{
|
||||
group_id_caster = GetGroup()->GetID();
|
||||
}
|
||||
else if(caster->IsRaidGrouped())
|
||||
{
|
||||
group_id_caster = (GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (GetRaid()->GetGroup(CastToClient()) + 1);
|
||||
// Is there a message generated? Too disgusted by raids.
|
||||
uint32 time = spell.base[i] * 10 * 1000;
|
||||
if (caster->IsClient()) {
|
||||
if (caster->IsGrouped()) {
|
||||
auto group = caster->GetGroup();
|
||||
for (int i = 0; i < 6; ++i)
|
||||
if (group->members[i])
|
||||
group->members[i]->aa_timers[aaTimerWarcry].Start(time);
|
||||
} else if (caster->IsRaidGrouped()) {
|
||||
auto raid = caster->GetRaid();
|
||||
uint32 gid = raid->GetGroup(caster->CastToClient());
|
||||
if (gid < 12)
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; ++i)
|
||||
if (raid->members[i].member && raid->members[i].GroupNumber == gid)
|
||||
raid->members[i].member->aa_timers[aaTimerWarcry].Start(time);
|
||||
}
|
||||
}
|
||||
if(group_id_caster){
|
||||
Group *g = entity_list.GetGroupByID(group_id_caster);
|
||||
uint32 time = spell.base[i]*10;
|
||||
if(g){
|
||||
for(int gi=0; gi < 6; gi++){
|
||||
if(g->members[gi] && g->members[gi]->IsClient())
|
||||
{
|
||||
g->members[gi]->CastToClient()->EnableAAEffect(aaEffectWarcry , time);
|
||||
if (g->members[gi]->GetID() != caster->GetID())
|
||||
g->members[gi]->Message(13, "You hear the war cry.");
|
||||
else
|
||||
Message(13, "You let loose a fierce war cry.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
CastToClient()->EnableAAEffect(aaEffectWarcry , time);
|
||||
Message(13, "You let loose a fierce war cry.");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1788,9 +1770,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
#endif
|
||||
|
||||
if(spells[spell_id].base2[i] == 0)
|
||||
AddProcToWeapon(procid, false, 100, spell_id, level_override);
|
||||
AddProcToWeapon(procid, false, 100, spell_id, caster_level);
|
||||
else
|
||||
AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100, spell_id, level_override);
|
||||
AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100, spell_id, caster_level);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2232,12 +2214,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
|
||||
case SE_AEMelee:
|
||||
{
|
||||
//old aa
|
||||
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Duration Rampage");
|
||||
#endif
|
||||
if (caster && caster->IsClient()) { // will tidy this up later so that NPCs can duration ramp from spells too
|
||||
CastToClient()->DurationRampage(effect_value*12);
|
||||
}
|
||||
aa_timers[aaTimerRampage].Start(effect_value * 10 * 1000); // Live bug, was suppose to be 1 second per value
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2966,7 +2948,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
case SE_FcIncreaseNumHits:
|
||||
case SE_CastonFocusEffect:
|
||||
case SE_FcHealAmtIncoming:
|
||||
case SE_MeleeVulnerability:
|
||||
case SE_LimitManaMax:
|
||||
case SE_DoubleRangedAttack:
|
||||
case SE_ShieldEquipHateMod:
|
||||
case SE_ShieldEquipDmgMod:
|
||||
@ -3374,7 +3356,7 @@ void Mob::BuffProcess()
|
||||
{
|
||||
--buffs[buffs_i].ticsremaining;
|
||||
|
||||
if ((buffs[buffs_i].ticsremaining == 0 && !IsShortDurationBuff(buffs[buffs_i].spellid)) || buffs[buffs_i].ticsremaining < 0) {
|
||||
if ((buffs[buffs_i].ticsremaining == 0 && !(IsShortDurationBuff(buffs[buffs_i].spellid) || IsBardSong(buffs[buffs_i].spellid))) || buffs[buffs_i].ticsremaining < 0) {
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Buff %d in slot %d has expired. Fading.", buffs[buffs_i].spellid, buffs_i);
|
||||
BuffFadeBySlot(buffs_i);
|
||||
}
|
||||
@ -3435,11 +3417,6 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
|
||||
}
|
||||
}
|
||||
|
||||
// Check for non buff spell effects to fade
|
||||
// AE melee effects
|
||||
if (IsClient())
|
||||
CastToClient()->CheckAAEffect(aaEffectRampage);
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (IsBlankSpellEffect(buff.spellid, i))
|
||||
continue;
|
||||
@ -4149,44 +4126,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
CalcBonuses();
|
||||
}
|
||||
|
||||
int32 Client::GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2)
|
||||
{
|
||||
int32 aa_effects_data[3] = { 0 };
|
||||
uint32 effect = 0;
|
||||
int32 base1 = 0;
|
||||
int32 base2 = 0;
|
||||
uint32 slot = 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)
|
||||
{
|
||||
effect = iter->second.skill_id;
|
||||
base1 = iter->second.base1;
|
||||
base2 = iter->second.base2;
|
||||
slot = iter->second.slot;
|
||||
|
||||
if (slot && slot == slot_id) {
|
||||
|
||||
if (GetEffect)
|
||||
return effect;
|
||||
|
||||
if (GetBase1)
|
||||
return base1;
|
||||
|
||||
if (GetBase2)
|
||||
return base2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
int16 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
||||
{
|
||||
const SPDat_Spell_Struct &spell = spells[spell_id];
|
||||
|
||||
@ -4201,7 +4141,8 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
|
||||
bool LimitFailure = false;
|
||||
bool LimitInclude[MaxLimitInclude] = {false};
|
||||
/* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice spells.
|
||||
/* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice
|
||||
spells.
|
||||
0/1 SE_LimitResist
|
||||
2/3 SE_LimitSpell
|
||||
4/5 SE_LimitEffect
|
||||
@ -4214,18 +4155,11 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
*/
|
||||
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)
|
||||
{
|
||||
effect = iter->second.skill_id;
|
||||
base1 = iter->second.base1;
|
||||
base2 = iter->second.base2;
|
||||
slot = iter->second.slot;
|
||||
for (const auto &e : rank.effects) {
|
||||
effect = e.effect_id;
|
||||
base1 = e.base1;
|
||||
base2 = e.base2;
|
||||
slot = e.slot;
|
||||
|
||||
/*
|
||||
AA Foci's can contain multiple focus effects within the same AA.
|
||||
@ -4259,9 +4193,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (effect)
|
||||
{
|
||||
switch (effect) {
|
||||
case SE_Blank:
|
||||
break;
|
||||
|
||||
@ -4271,8 +4203,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (base1 < 0) {
|
||||
if (spell.resisttype == -base1) // Exclude
|
||||
LimitFailure = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[0] = true;
|
||||
if (spell.resisttype == base1) // Include
|
||||
LimitInclude[1] = true;
|
||||
@ -4290,14 +4221,15 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
case SE_LimitMaxLevel:
|
||||
spell_level = spell.classes[(GetClass() % 16) - 1];
|
||||
lvldiff = spell_level - base1;
|
||||
//every level over cap reduces the effect by base2 percent unless from a clicky when ItemCastsUseFocus is true
|
||||
if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) {
|
||||
// every level over cap reduces the effect by base2 percent unless from a clicky when
|
||||
// ItemCastsUseFocus is true
|
||||
if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) ||
|
||||
RuleB(Character, ItemCastsUseFocus) == false)) {
|
||||
if (base2 > 0) {
|
||||
lvlModifier -= base2 * lvldiff;
|
||||
if (lvlModifier < 1)
|
||||
LimitFailure = true;
|
||||
}
|
||||
else
|
||||
} else
|
||||
LimitFailure = true;
|
||||
}
|
||||
break;
|
||||
@ -4321,8 +4253,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (base1 < 0) { // Exclude
|
||||
if (spell_id == -base1)
|
||||
LimitFailure = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[2] = true;
|
||||
if (spell_id == base1) // Include
|
||||
LimitInclude[3] = true;
|
||||
@ -4339,17 +4270,21 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (base1 < 0) {
|
||||
if (IsEffectInSpell(spell_id, -base1)) // Exclude
|
||||
LimitFailure = true;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
LimitInclude[4] = true;
|
||||
// they use 33 here for all classes ... unsure if the type check is really needed
|
||||
if (base1 == SE_SummonPet && type == focusReagentCost) {
|
||||
if (IsSummonPetSpell(spell_id) || IsSummonSkeletonSpell(spell_id))
|
||||
LimitInclude[5] = true;
|
||||
} else {
|
||||
if (IsEffectInSpell(spell_id, base1)) // Include
|
||||
LimitInclude[5] = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_LimitSpellType:
|
||||
switch(base1)
|
||||
{
|
||||
switch (base1) {
|
||||
case 0:
|
||||
if (!IsDetrimentalSpell(spell_id))
|
||||
LimitFailure = true;
|
||||
@ -4366,12 +4301,16 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
LimitFailure = true;
|
||||
break;
|
||||
|
||||
case SE_LimitManaMax:
|
||||
if (spell.mana > base1)
|
||||
LimitFailure = true;
|
||||
break;
|
||||
|
||||
case SE_LimitTarget:
|
||||
if (base1 < 0) {
|
||||
if (-base1 == spell.targettype) // Exclude
|
||||
LimitFailure = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[6] = true;
|
||||
if (base1 == spell.targettype) // Include
|
||||
LimitInclude[7] = true;
|
||||
@ -4390,8 +4329,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (base1 < 0) {
|
||||
if (-base1 == spell.spellgroup) // Exclude
|
||||
LimitFailure = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[8] = true;
|
||||
if (base1 == spell.spellgroup) // Include
|
||||
LimitInclude[9] = true;
|
||||
@ -4402,8 +4340,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (base1 < 0) {
|
||||
if (-base1 == spell.skill)
|
||||
LimitFailure = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[10] = true;
|
||||
if (base1 == spell.skill)
|
||||
LimitInclude[11] = true;
|
||||
@ -4414,8 +4351,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (base1 < 0) { // Exclude
|
||||
if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass))
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[12] = true;
|
||||
if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) // Include
|
||||
LimitInclude[13] = true;
|
||||
@ -4426,8 +4362,7 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (base1 < 0) { // Exclude
|
||||
if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass))
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[14] = true;
|
||||
if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) // Include
|
||||
LimitInclude[15] = true;
|
||||
@ -4435,7 +4370,8 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
break;
|
||||
|
||||
case SE_LimitClass:
|
||||
//Do not use this limit more then once per spell. If multiple class, treat value like items would.
|
||||
// Do not use this limit more then once per spell. If multiple class, treat value like items
|
||||
// would.
|
||||
if (!PassLimitClass(base1, GetClass()))
|
||||
LimitFailure = true;
|
||||
break;
|
||||
@ -4517,13 +4453,11 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (value > 0) {
|
||||
if (base1 > value)
|
||||
value = base1;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
if (base1 < value)
|
||||
value = base1;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
value = base1;
|
||||
}
|
||||
break;
|
||||
@ -4636,7 +4570,6 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
if (type == focusFcStunTimeMod)
|
||||
value = base1;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -4653,12 +4586,11 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
|
||||
//given an item/spell's focus ID and the spell being cast, determine the focus ammount, if any
|
||||
//assumes that spell_id is not a bard spell and that both ids are valid spell ids
|
||||
int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, bool best_focus) {
|
||||
|
||||
int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, bool best_focus)
|
||||
{
|
||||
if (!IsValidSpell(focus_id) || !IsValidSpell(spell_id))
|
||||
return 0;
|
||||
|
||||
|
||||
const SPDat_Spell_Struct &focus_spell = spells[focus_id];
|
||||
const SPDat_Spell_Struct &spell = spells[spell_id];
|
||||
|
||||
@ -4669,7 +4601,8 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
uint32 Caston_spell_id = 0;
|
||||
|
||||
bool LimitInclude[MaxLimitInclude] = {false};
|
||||
/* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice spells.
|
||||
/* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice
|
||||
spells.
|
||||
0/1 SE_LimitResist
|
||||
2/3 SE_LimitSpell
|
||||
4/5 SE_LimitEffect
|
||||
@ -4692,8 +4625,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base[i] < 0) {
|
||||
if (spell.resisttype == -focus_spell.base[i]) // Exclude
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[0] = true;
|
||||
if (spell.resisttype == focus_spell.base[i]) // Include
|
||||
LimitInclude[1] = true;
|
||||
@ -4713,14 +4645,15 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
break;
|
||||
spell_level = spell.classes[(GetClass() % 16) - 1];
|
||||
lvldiff = spell_level - focus_spell.base[i];
|
||||
//every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky when ItemCastsUseFocus is true
|
||||
if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)){
|
||||
// every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky
|
||||
// when ItemCastsUseFocus is true
|
||||
if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) ||
|
||||
RuleB(Character, ItemCastsUseFocus) == false)) {
|
||||
if (focus_spell.base2[i] > 0) {
|
||||
lvlModifier -= focus_spell.base2[i] * lvldiff;
|
||||
if (lvlModifier < 1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@ -4746,8 +4679,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base[i] < 0) { // Exclude
|
||||
if (spell_id == -focus_spell.base[i])
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[2] = true;
|
||||
if (spell_id == focus_spell.base[i]) // Include
|
||||
LimitInclude[3] = true;
|
||||
@ -4755,7 +4687,8 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
break;
|
||||
|
||||
case SE_LimitMinDur:
|
||||
if (focus_spell.base[i] > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration))
|
||||
if (focus_spell.base[i] >
|
||||
CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration))
|
||||
return (0);
|
||||
break;
|
||||
|
||||
@ -4763,15 +4696,13 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base[i] < 0) {
|
||||
if (IsEffectInSpell(spell_id, -focus_spell.base[i])) // Exclude
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
LimitInclude[4] = true;
|
||||
if (IsEffectInSpell(spell_id, focus_spell.base[i])) // Include
|
||||
LimitInclude[5] = true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case SE_LimitSpellType:
|
||||
switch (focus_spell.base[i]) {
|
||||
case 0:
|
||||
@ -4783,7 +4714,8 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown limit spelltype %d", focus_spell.base[i]);
|
||||
Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown limit spelltype %d",
|
||||
focus_spell.base[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -4792,12 +4724,16 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SE_LimitManaMax:
|
||||
if (spell.mana > focus_spell.base[i])
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SE_LimitTarget:
|
||||
if (focus_spell.base[i] < 0) {
|
||||
if (-focus_spell.base[i] == spell.targettype) // Exclude
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[6] = true;
|
||||
if (focus_spell.base[i] == spell.targettype) // Include
|
||||
LimitInclude[7] = true;
|
||||
@ -4805,9 +4741,11 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
break;
|
||||
|
||||
case SE_LimitCombatSkills:
|
||||
if (focus_spell.base[i] == 0 && (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) //Exclude Discs / Procs
|
||||
if (focus_spell.base[i] == 0 &&
|
||||
(IsCombatSkill(spell_id) || IsCombatProc(spell_id))) // Exclude Discs / Procs
|
||||
return 0;
|
||||
else if (focus_spell.base[i] == 1 && (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) //Exclude Spells
|
||||
else if (focus_spell.base[i] == 1 &&
|
||||
(!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) // Exclude Spells
|
||||
return 0;
|
||||
|
||||
break;
|
||||
@ -4816,8 +4754,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base[i] < 0) {
|
||||
if (-focus_spell.base[i] == spell.spellgroup) // Exclude
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[8] = true;
|
||||
if (focus_spell.base[i] == spell.spellgroup) // Include
|
||||
LimitInclude[9] = true;
|
||||
@ -4828,8 +4765,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base[i] < 0) {
|
||||
if (-focus_spell.base[i] == spell.skill)
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[10] = true;
|
||||
if (focus_spell.base[i] == spell.skill)
|
||||
LimitInclude[11] = true;
|
||||
@ -4837,7 +4773,8 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
break;
|
||||
|
||||
case SE_LimitClass:
|
||||
//Do not use this limit more then once per spell. If multiple class, treat value like items would.
|
||||
// Do not use this limit more then once per spell. If multiple class, treat value like items
|
||||
// would.
|
||||
if (!PassLimitClass(focus_spell.base[i], GetClass()))
|
||||
return 0;
|
||||
break;
|
||||
@ -4866,8 +4803,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base[i] < 0) { // Exclude
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass))
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[12] = true;
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) // Include
|
||||
LimitInclude[13] = true;
|
||||
@ -4878,15 +4814,13 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base[i] < 0) { // Exclude
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass))
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LimitInclude[14] = true;
|
||||
if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) // Include
|
||||
LimitInclude[15] = true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// handle effects
|
||||
case SE_ImprovedDamage:
|
||||
if (type == focusImprovedDamage) {
|
||||
@ -4896,7 +4830,8 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (focus_spell.base2[i] != 0) {
|
||||
value = focus_spell.base2[i];
|
||||
}
|
||||
// If the spell does not contain a base2 value, then its a straight non random value
|
||||
// If the spell does not contain a base2 value, then its a straight non random
|
||||
// value
|
||||
else {
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
@ -4904,8 +4839,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
// Actual focus calculation starts here
|
||||
else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) {
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]);
|
||||
}
|
||||
}
|
||||
@ -4916,15 +4850,12 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (best_focus) {
|
||||
if (focus_spell.base2[i] != 0) {
|
||||
value = focus_spell.base2[i];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
}
|
||||
else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) {
|
||||
} else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) {
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]);
|
||||
}
|
||||
}
|
||||
@ -4935,15 +4866,12 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (best_focus) {
|
||||
if (focus_spell.base2[i] != 0) {
|
||||
value = focus_spell.base2[i];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
}
|
||||
else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) {
|
||||
} else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) {
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]);
|
||||
}
|
||||
}
|
||||
@ -4995,13 +4923,11 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
if (value > 0) {
|
||||
if (focus_spell.base[i] > value)
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
if (focus_spell.base[i] < value)
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
value = focus_spell.base[i];
|
||||
}
|
||||
break;
|
||||
@ -5122,10 +5048,10 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
// this spits up a lot of garbage when calculating spell focuses
|
||||
// since they have all kinds of extra effects on them.
|
||||
default:
|
||||
Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown effectid %d", focus_spell.effectid[i]);
|
||||
Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown effectid %d",
|
||||
focus_spell.effectid[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int e = 0; e < MaxLimitInclude; e += 2) {
|
||||
@ -5227,31 +5153,31 @@ uint16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
/*Note: At present, ff designing custom AA to have a sympathetic proc effect, only use one focus
|
||||
effect within the aa_effects data for each AA*[No live AA's use this effect to my knowledge]*/
|
||||
if (aabonuses.FocusEffects[type]) {
|
||||
|
||||
uint32 aa_AA = 0;
|
||||
uint32 aa_value = 0;
|
||||
|
||||
for (int i = 0; i < MAX_PP_AA_ARRAY; i++)
|
||||
{
|
||||
aa_AA = this->aa[i]->AA;
|
||||
aa_value = this->aa[i]->value;
|
||||
if (aa_AA < 1 || aa_value < 1)
|
||||
continue;
|
||||
|
||||
for (const auto &aa : aa_ranks) {
|
||||
if (SympatheticProcList.size() > MAX_SYMPATHETIC_PROCS)
|
||||
break;
|
||||
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
|
||||
if(!ability) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rank->effects.empty())
|
||||
continue;
|
||||
|
||||
proc_spellid = CalcAAFocus(type, aa_AA, spell_id);
|
||||
|
||||
proc_spellid = CalcAAFocus(type, *rank, spell_id);
|
||||
if (IsValidSpell(proc_spellid)) {
|
||||
ProcChance = GetSympatheticProcChances(spell_id, GetAABase1(aa_AA, 1));
|
||||
ProcChance = GetSympatheticProcChances(spell_id, rank->effects[0].base1);
|
||||
if (zone->random.Roll(ProcChance))
|
||||
SympatheticProcList.push_back(proc_spellid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SympatheticProcList.size() > 0)
|
||||
if (!SympatheticProcList.empty())
|
||||
{
|
||||
uint8 random = zone->random.Int(0, SympatheticProcList.size()-1);
|
||||
int FinalSympatheticProc = SympatheticProcList[random];
|
||||
@ -5262,9 +5188,9 @@ uint16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 Client::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
|
||||
if (IsBardSong(spell_id) && type != focusFcBaseEffects)
|
||||
int16 Client::GetFocusEffect(focusType type, uint16 spell_id)
|
||||
{
|
||||
if (IsBardSong(spell_id) && type != focusFcBaseEffects && type != focusSpellDuration)
|
||||
return 0;
|
||||
|
||||
int16 realTotal = 0;
|
||||
@ -5499,18 +5425,20 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
if (aabonuses.FocusEffects[type]){
|
||||
|
||||
int16 Total3 = 0;
|
||||
uint32 slots = 0;
|
||||
uint32 aa_AA = 0;
|
||||
uint32 aa_value = 0;
|
||||
|
||||
for (int i = 0; i < MAX_PP_AA_ARRAY; i++)
|
||||
{
|
||||
aa_AA = this->aa[i]->AA;
|
||||
aa_value = this->aa[i]->value;
|
||||
if (aa_AA < 1 || aa_value < 1)
|
||||
for (const auto &aa : aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
|
||||
if(!ability) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rank->effects.empty())
|
||||
continue;
|
||||
|
||||
Total3 = CalcAAFocus(type, aa_AA, spell_id);
|
||||
Total3 = CalcAAFocus(type, *rank, spell_id);
|
||||
if (Total3 > 0 && realTotal3 >= 0 && Total3 > realTotal3) {
|
||||
realTotal3 = Total3;
|
||||
}
|
||||
@ -5520,9 +5448,6 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) {
|
||||
}
|
||||
}
|
||||
|
||||
if(type == focusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact))
|
||||
return 100;
|
||||
|
||||
if(type == focusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id)))
|
||||
return 0;
|
||||
//Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected
|
||||
|
||||
@ -146,7 +146,8 @@ void NPC::SpellProcess()
|
||||
// to allow procs to work
|
||||
bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 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",
|
||||
(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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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,
|
||||
int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish,
|
||||
uint32 item_slot, uint32 timer, uint32 timer_duration, uint32 type,
|
||||
int16 resist_adjust)
|
||||
uint32 item_slot, uint32 timer, uint32 timer_duration,
|
||||
int16 resist_adjust, uint32 aa_id)
|
||||
{
|
||||
Mob* pMob = nullptr;
|
||||
int32 orgcasttime;
|
||||
@ -361,7 +362,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
casting_spell_timer = timer;
|
||||
casting_spell_timer_duration = timer_duration;
|
||||
}
|
||||
casting_spell_type = type;
|
||||
casting_spell_aa_id = aa_id;
|
||||
|
||||
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);
|
||||
@ -408,24 +409,19 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
// ok now we know the target
|
||||
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 = 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
|
||||
// fix: items dont need mana :-/
|
||||
// If you're at full mana, let it cast even if you dont have enough mana
|
||||
|
||||
// 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_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...
|
||||
if(IsNPC() && my_curmana == my_maxmana)
|
||||
@ -783,9 +779,9 @@ void Mob::ZeroCastingVars()
|
||||
casting_spell_inventory_slot = 0;
|
||||
casting_spell_timer = 0;
|
||||
casting_spell_timer_duration = 0;
|
||||
casting_spell_type = 0;
|
||||
casting_spell_resist_adjust = 0;
|
||||
casting_spell_checks = false;
|
||||
casting_spell_aa_id = 0;
|
||||
delaytimer = false;
|
||||
}
|
||||
|
||||
@ -816,10 +812,9 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
|
||||
CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot);
|
||||
}
|
||||
|
||||
if(casting_spell_type == 1 && IsClient()) { //Rest AA Timer on failed cast
|
||||
CastToClient()->SendAATimer(casting_spell_timer - pTimerAAStart, 0, 0xFFFFFF);
|
||||
CastToClient()->Message_StringID(15,ABILITY_FAILED);
|
||||
CastToClient()->GetPTimers().Clear(&database, casting_spell_timer);
|
||||
if(casting_spell_aa_id && IsClient()) { //Rest AA Timer on failed cast
|
||||
CastToClient()->Message_StringID(MT_SpellFailure, ABILITY_FAILED);
|
||||
CastToClient()->ResetAlternateAdvancementTimer(casting_spell_aa_id);
|
||||
}
|
||||
|
||||
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)) {
|
||||
if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
|
||||
// Prevent mana usage/timers being set for beneficial buffs
|
||||
if(casting_spell_type == 1)
|
||||
if(casting_spell_aa_id)
|
||||
InterruptSpell();
|
||||
return false;
|
||||
}
|
||||
@ -2157,11 +2152,11 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
}
|
||||
#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())
|
||||
{
|
||||
SpellOnTarget(spell_id, this);
|
||||
entity_list.MassGroupBuff(this, this, spell_id, true);
|
||||
SetMGB(false);
|
||||
}
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
if (!DoHPToManaCovert(mana_used))
|
||||
if (!DoHPToManaCovert(mana_used)) {
|
||||
SetMana(GetMana() - mana_used);
|
||||
TryTriggerOnValueAmount(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
//set our reuse timer on long ass reuse_time spells...
|
||||
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);
|
||||
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
|
||||
// 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());
|
||||
if(casting_spell_type != 1) // AA is handled differently
|
||||
if(casting_spell_aa_id)
|
||||
Message_StringID(MT_SpellFailure, SPELL_NO_HOLD);
|
||||
safe_delete(action_packet);
|
||||
return false;
|
||||
@ -4116,8 +4127,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (IsClient() && CastToClient()->CheckAAEffect(aaEffectWarcry))
|
||||
else if (CheckAATimer(aaTimerWarcry))
|
||||
{
|
||||
Message(13, "Your are immune to fear.");
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Clients has WarCry effect, immune to fear!");
|
||||
|
||||
@ -179,10 +179,10 @@ bool TitleManager::IsClientEligibleForTitle(Client *c, std::vector<TitleEntry>::
|
||||
if((Title->Class >= 0) && (c->GetBaseClass() != Title->Class))
|
||||
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;
|
||||
|
||||
if((Title->MaxAAPoints >= 0) && (c->GetAAPointsSpent() > static_cast<uint32>(Title->MaxAAPoints)))
|
||||
if((Title->MaxAAPoints >= 0) && (c->GetSpentAA() > static_cast<uint32>(Title->MaxAAPoints)))
|
||||
return false;
|
||||
|
||||
if(Title->SkillID >= 0)
|
||||
|
||||
@ -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);
|
||||
|
||||
//fix up pathing Z
|
||||
if(zone->HasMap() && RuleB(Map, FixPathingZAtWaypoints))
|
||||
if(zone->HasMap() && RuleB(Map, FixPathingZAtWaypoints) && !IsBoat())
|
||||
{
|
||||
|
||||
if(!RuleB(Watermap, CheckForWaterAtWaypoints) || !zone->HasWaterMap() ||
|
||||
@ -443,31 +443,10 @@ void NPC::NextGuardPosition() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// we need this for charmed NPCs
|
||||
void Mob::SaveSpawnSpot() {
|
||||
spawn_x = x_pos;
|
||||
spawn_y = y_pos;
|
||||
spawn_z = z_pos;
|
||||
spawn_heading = heading;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*float Mob::CalculateDistanceToNextWaypoint() {
|
||||
return CalculateDistance(cur_wp_x, cur_wp_y, cur_wp_z);
|
||||
}*/
|
||||
|
||||
float Mob::CalculateDistance(float x, float y, float z) {
|
||||
return (float)sqrtf( ((m_Position.x-x)*(m_Position.x-x)) + ((m_Position.y-y)*(m_Position.y-y)) + ((m_Position.z-z)*(m_Position.z-z)) );
|
||||
}
|
||||
|
||||
/*
|
||||
uint8 NPC::CalculateHeadingToNextWaypoint() {
|
||||
return CalculateHeadingToTarget(cur_wp_x, cur_wp_y);
|
||||
}
|
||||
*/
|
||||
float Mob::CalculateHeadingToTarget(float in_x, float in_y) {
|
||||
float angle;
|
||||
|
||||
@ -521,7 +500,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
||||
@ -597,7 +576,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
|
||||
pRunAnimSpeed = speed;
|
||||
if(IsClient())
|
||||
{
|
||||
animation = speed;
|
||||
animation = speed / 2;
|
||||
}
|
||||
//pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO);
|
||||
//speed *= NPC_SPEED_MULTIPLIER;
|
||||
@ -611,7 +590,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
|
||||
tar_vector = (float)speed / mag;
|
||||
|
||||
// mob move fix
|
||||
int numsteps = (int) ( mag * 16.0f / (float)speed);
|
||||
int numsteps = (int) ( mag * 16.0f / (float)speed + 0.5f);
|
||||
|
||||
|
||||
// mob move fix
|
||||
@ -621,9 +600,9 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
|
||||
if (numsteps>1)
|
||||
{
|
||||
tar_vector=1.0f ;
|
||||
m_TargetV.x = 1.25f * m_TargetV.x/(float)numsteps;
|
||||
m_TargetV.y = 1.25f * m_TargetV.y/(float)numsteps;
|
||||
m_TargetV.z = 1.25f *m_TargetV.z/(float)numsteps;
|
||||
m_TargetV.x = m_TargetV.x/(float)numsteps;
|
||||
m_TargetV.y = m_TargetV.y/(float)numsteps;
|
||||
m_TargetV.z = m_TargetV.z/(float)numsteps;
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x;
|
||||
float new_y = m_Position.y + m_TargetV.y;
|
||||
@ -636,7 +615,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
|
||||
m_Position.y = new_y;
|
||||
m_Position.z = new_z;
|
||||
m_Position.w = CalculateHeadingToTarget(x, y);
|
||||
tar_ndx = 22 - numsteps;
|
||||
tar_ndx = 20 - numsteps;
|
||||
Log.Out(Logs::Detail, Logs::AI, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", m_Position.x, m_Position.y, m_Position.z, numsteps);
|
||||
}
|
||||
else
|
||||
@ -656,6 +635,11 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
|
||||
|
||||
else {
|
||||
tar_vector/=16.0f;
|
||||
float dur = Timer::GetCurrentTime() - pLastChange;
|
||||
if(dur < 1.0f) {
|
||||
dur = 1.0f;
|
||||
}
|
||||
tar_vector = (tar_vector * AImovement_duration) / 100.0f;
|
||||
|
||||
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
||||
float new_y = m_Position.y + m_TargetV.y*tar_vector;
|
||||
@ -717,8 +701,6 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, boo
|
||||
}
|
||||
else
|
||||
{
|
||||
// force an update now
|
||||
move_tic_count = RuleI(Zone, NPCPositonUpdateTicCount);
|
||||
SendPosUpdate();
|
||||
SetAppearance(eaStanding, false);
|
||||
}
|
||||
|
||||
@ -1931,10 +1931,10 @@ bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_nu
|
||||
|
||||
bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...) {
|
||||
va_list argptr;
|
||||
char buffer[256];
|
||||
char buffer[4096] = { 0 };
|
||||
|
||||
va_start(argptr, message);
|
||||
vsnprintf(buffer, 256, message, argptr);
|
||||
vsnprintf(buffer, sizeof(buffer) - 1, message, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
return SendEmoteMessage(to, to_guilddbid, 0, type, buffer);
|
||||
@ -1942,10 +1942,10 @@ bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 t
|
||||
|
||||
bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...) {
|
||||
va_list argptr;
|
||||
char buffer[256];
|
||||
char buffer[4096] = { 0 };
|
||||
|
||||
va_start(argptr, message);
|
||||
vsnprintf(buffer, 256, message, argptr);
|
||||
vsnprintf(buffer, sizeof(buffer) - 1, message, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
if (!Connected() && to == 0) {
|
||||
|
||||
@ -68,7 +68,6 @@ extern bool staticzone;
|
||||
extern NetConnection net;
|
||||
extern PetitionList petition_list;
|
||||
extern QuestParserCollection* parse;
|
||||
extern uint16 adverrornum;
|
||||
extern uint32 numclients;
|
||||
extern WorldServer worldserver;
|
||||
extern Zone* zone;
|
||||
@ -805,8 +804,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
weather_intensity = 0;
|
||||
blocked_spells = nullptr;
|
||||
totalBS = 0;
|
||||
aas = nullptr;
|
||||
totalAAs = 0;
|
||||
zone_has_current_time = false;
|
||||
|
||||
Instance_Shutdown_Timer = nullptr;
|
||||
@ -865,16 +862,6 @@ Zone::~Zone() {
|
||||
safe_delete(qGlobals);
|
||||
safe_delete_array(adv_data);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -953,16 +940,12 @@ bool Zone::Init(bool iStaticZone) {
|
||||
zone->LoadAlternateCurrencies();
|
||||
zone->LoadNPCEmotes(&NPCEmoteList);
|
||||
|
||||
//Load AA information
|
||||
adverrornum = 500;
|
||||
LoadAAs();
|
||||
LoadAlternateAdvancement();
|
||||
|
||||
//Load merchant data
|
||||
adverrornum = 501;
|
||||
zone->GetMerchantDataForZoneLoad();
|
||||
|
||||
//Load temporary merchant data
|
||||
adverrornum = 502;
|
||||
zone->LoadTempMerchantData();
|
||||
|
||||
// Merc data
|
||||
@ -974,7 +957,6 @@ bool Zone::Init(bool iStaticZone) {
|
||||
if (RuleB(Zone, LevelBasedEXPMods))
|
||||
zone->LoadLevelEXPMods();
|
||||
|
||||
adverrornum = 503;
|
||||
petition_list.ClearPetitions();
|
||||
petition_list.ReadDatabase();
|
||||
|
||||
|
||||
20
zone/zone.h
20
zone/zone.h
@ -27,6 +27,7 @@
|
||||
#include "qglobals.h"
|
||||
#include "spawn2.h"
|
||||
#include "spawngroup.h"
|
||||
#include "aa_ability.h"
|
||||
|
||||
struct ZonePoint
|
||||
{
|
||||
@ -113,11 +114,13 @@ public:
|
||||
|
||||
inline const uint32& GetMaxClients() { return pMaxClients; }
|
||||
|
||||
void LoadAAs();
|
||||
int GetTotalAAs() { return totalAAs; }
|
||||
SendAA_Struct* GetAABySequence(uint32 seq) { return aas[seq]; }
|
||||
SendAA_Struct* FindAA(uint32 id);
|
||||
uint8 GetTotalAALevels(uint32 skill_id);
|
||||
//new AA
|
||||
void LoadAlternateAdvancement();
|
||||
AA::Ability *GetAlternateAdvancementAbility(int id);
|
||||
AA::Ability *GetAlternateAdvancementAbilityByRank(int rank_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);
|
||||
bool LoadZoneObjects();
|
||||
bool LoadGroundSpawns();
|
||||
@ -193,6 +196,10 @@ public:
|
||||
char *adv_data;
|
||||
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 DoAdventureAssassinationCountIncrease();
|
||||
void DoAdventureActions();
|
||||
@ -313,9 +320,6 @@ private:
|
||||
int totalBS;
|
||||
ZoneSpellsBlocked *blocked_spells;
|
||||
|
||||
int totalAAs;
|
||||
SendAA_Struct **aas; //array of AA structs
|
||||
|
||||
/*
|
||||
Spawn related things
|
||||
*/
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "position.h"
|
||||
#include "../common/faction.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "aa_ability.h"
|
||||
|
||||
class Client;
|
||||
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 LoadFactionData();
|
||||
|
||||
/* AAs */
|
||||
bool LoadAAEffects();
|
||||
bool LoadAAEffects2();
|
||||
bool LoadSwarmSpells();
|
||||
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);
|
||||
/* AAs New */
|
||||
bool LoadAlternateAdvancementAbilities(std::unordered_map<int, std::unique_ptr<AA::Ability>> &abilities,
|
||||
std::unordered_map<int, std::unique_ptr<AA::Rank>> &ranks);
|
||||
bool LoadAlternateAdvancement(Client *c);
|
||||
|
||||
/* 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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user