Merge branch 'master' of github.com:EQEmu/Server

This commit is contained in:
KimLS 2014-02-22 15:04:18 -08:00
commit 0e44a3625c
43 changed files with 1292 additions and 710 deletions

View File

@ -1,5 +1,30 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 02/20/2014 ==
Kayen: Implemented SE_MitigateDotDamage - dot spell mitigation rune with max value
Kayen: Implemented SE_DistanceRemoval - removed from target when target moves X amount of distance away from where initially hit.
Required SQL: utils/sql/git/2014_02_20_buff_updates.sql
== 02/18/2014 ==
Kayen: Implemented SE_TriggerOnReqCaster - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist)
Kayen: Implemented SE_ImprovedTaunt - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y
Kayen: Fixed an error where SE_ChangeAggro was adding its bonus x 2 for spell generated aggro. (this applies also to spell casting subtlety AA reduction)
== 02/14/2014 ==
Kayen: Fixes for buffs not fading under certain conditions in revised numhits system, and other fixes.
Kayen: Implemented support for spell_new field CastRestrictions (limits what type of targets spells can effect).
*A detailed list describing what the values used in this field do can be found in Mob::PassCastRestriction*
Kayen: Implemented support for spell_new field not_reflectable, no_partial_resists.
Required SQL: utils/sql/git/2014_02_13_spells_new_updates.sql
Names many unknown fields in the table.
== 02/13/2014 ==
Sorvani: Renamed the instance_lockout and instance_lockout_player tables to instance_list and instance_list_player. Cleaned up the Database::GetUnusedInstanceID logic.
Required SQL: utils/sql/git/2014_02_13_Rename_instance_lockout_tables.sql
== 02/10/2014 ==
demonstar55 (Secrets): Re-wrote the entity list to be a std::map. This should be used for direct entityID lookups and is noticably faster performance-wise. Also should result in less nil pointers potentially.
Secrets: Fixed a crash issue that could occur on #repop related to quest timers.

View File

@ -144,7 +144,7 @@ void EQStreamFactory::Push(EQStream *s)
void EQStreamFactory::ReaderLoop()
{
fd_set readset;
std::map<std::string,EQStream *>::iterator stream_itr;
std::map<std::pair<uint32, uint16>,EQStream *>::iterator stream_itr;
int num;
int length;
unsigned char buffer[2048];
@ -183,14 +183,13 @@ timeval sleep_time;
{
// What do we wanna do?
} else {
char temp[25];
sprintf(temp,"%u.%d",ntohl(from.sin_addr.s_addr),ntohs(from.sin_port));
MStreams.lock();
if ((stream_itr=Streams.find(temp))==Streams.end()) {
stream_itr=Streams.find(std::make_pair(from.sin_addr.s_addr, from.sin_port));
if (stream_itr == Streams.end()) {
if (buffer[1]==OP_SessionRequest) {
EQStream *s = new EQStream(from);
s->SetStreamType(StreamType);
Streams[temp]=s;
Streams[std::make_pair(from.sin_addr.s_addr, from.sin_port)]=s;
WriterWork.Signal();
Push(s);
s->AddBytesRecv(length);
@ -225,7 +224,7 @@ void EQStreamFactory::CheckTimeout()
MStreams.lock();
unsigned long now=Timer::GetCurrentTime();
std::map<std::string,EQStream *>::iterator stream_itr;
std::map<std::pair<uint32, uint16>,EQStream *>::iterator stream_itr;
for(stream_itr=Streams.begin();stream_itr!=Streams.end();) {
EQStream *s = stream_itr->second;
@ -241,8 +240,8 @@ void EQStreamFactory::CheckTimeout()
} else {
//everybody is done, we can delete it now
//std::cout << "Removing connection" << std::endl;
std::map<std::string,EQStream *>::iterator temp=stream_itr;
stream_itr++;
std::map<std::pair<uint32, uint16>,EQStream *>::iterator temp=stream_itr;
++stream_itr;
//let whoever has the stream outside delete it
delete temp->second;
Streams.erase(temp);
@ -250,14 +249,14 @@ void EQStreamFactory::CheckTimeout()
}
}
stream_itr++;
++stream_itr;
}
MStreams.unlock();
}
void EQStreamFactory::WriterLoop()
{
std::map<std::string,EQStream *>::iterator stream_itr;
std::map<std::pair<uint32, uint16>,EQStream *>::iterator stream_itr;
bool havework=true;
std::vector<EQStream *> wants_write;
std::vector<EQStream *>::iterator cur,end;
@ -285,14 +284,14 @@ Timer DecayTimer(20);
//copy streams into a seperate list so we dont have to keep
//MStreams locked while we are writting
MStreams.lock();
for(stream_itr=Streams.begin();stream_itr!=Streams.end();stream_itr++) {
for(stream_itr=Streams.begin();stream_itr!=Streams.end();++stream_itr) {
// If it's time to decay the bytes sent, then let's do it before we try to write
if (decay)
stream_itr->second->Decay();
//bullshit checking, to see if this is really happening, GDB seems to think so...
if(stream_itr->second == nullptr) {
fprintf(stderr, "ERROR: nullptr Stream encountered in EQStreamFactory::WriterLoop for: %s", stream_itr->first.c_str());
fprintf(stderr, "ERROR: nullptr Stream encountered in EQStreamFactory::WriterLoop for: %i", stream_itr->first.first, stream_itr->first.second);
continue;
}
@ -307,7 +306,7 @@ Timer DecayTimer(20);
//do the actual writes
cur = wants_write.begin();
end = wants_write.end();
for(; cur != end; cur++) {
for(; cur != end; ++cur) {
(*cur)->Write(sock);
(*cur)->ReleaseFromUse();
}

View File

@ -27,7 +27,7 @@ class EQStreamFactory : private Timeoutable {
std::queue<EQStream *> NewStreams;
Mutex MNewStreams;
std::map<std::string,EQStream *> Streams;
std::map<std::pair<uint32, uint16>,EQStream *> Streams;
Mutex MStreams;
virtual void CheckTimeout();

View File

@ -11,7 +11,7 @@ EQStreamIdentifier::~EQStreamIdentifier() {
std::vector<Record *>::iterator cur, end;
cur = m_streams.begin();
end = m_streams.end();
for(; cur != end; cur++) {
for(; cur != end; ++cur) {
Record *r = *cur;
r->stream->ReleaseFromUse();
delete r;
@ -19,7 +19,7 @@ EQStreamIdentifier::~EQStreamIdentifier() {
std::vector<Patch *>::iterator curp, endp;
curp = m_patches.begin();
endp = m_patches.end();
for(; curp != endp; curp++) {
for(; curp != endp; ++curp) {
delete *curp;
}
}
@ -56,6 +56,7 @@ void EQStreamIdentifier::Process() {
//if stream hasn't finished initializing then continue;
if(r->stream->GetState() == UNESTABLISHED)
{
++cur;
continue;
}
if(r->stream->GetState() != ESTABLISHED) {
@ -93,7 +94,7 @@ void EQStreamIdentifier::Process() {
//foreach possbile patch...
curp = m_patches.begin();
endp = m_patches.end();
for(; !found_one && curp != endp; curp++) {
for(; !found_one && curp != endp; ++curp) {
Patch *p = *curp;
//ask the stream to see if it matches the supplied signature
@ -136,7 +137,7 @@ void EQStreamIdentifier::Process() {
delete r;
cur = m_streams.erase(cur);
} else {
cur++;
++cur;
}
} //end foreach stream
}

View File

@ -138,7 +138,7 @@ public:
iterator cur, end;
cur = streams.begin();
end = streams.end();
for(; cur != end; cur++) {
for(; cur != end; ++cur) {
if(cur->second == it) {
streams.erase(cur);
//lazy recursive delete for now, since we have to redo

View File

@ -668,7 +668,7 @@ bool Database::DeleteCharacter(char *name)
#if DEBUG >= 5
printf(" instances");
#endif
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE charid='%d'", charid), errbuf, nullptr, &affected_rows);
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE charid='%d'", charid), errbuf, nullptr, &affected_rows);
if(query)
{
safe_delete_array(query);
@ -2278,7 +2278,7 @@ bool Database::VerifyZoneInstance(uint32 zone_id, uint16 instance_id)
char *query = 0;
MYSQL_RES *result;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where id=%u AND zone=%u",
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id=%u AND zone=%u",
instance_id, zone_id), errbuf, &result))
{
safe_delete_array(query);
@ -2308,7 +2308,7 @@ bool Database::CharacterInInstanceGroup(uint16 instance_id, uint32 char_id)
MYSQL_RES *result;
bool lockout_instance_player = false;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_lockout_player where id=%u AND charid=%u",
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_list_player where id=%u AND charid=%u",
instance_id, char_id), errbuf, &result))
{
safe_delete_array(query);
@ -2330,10 +2330,10 @@ void Database::DeleteInstance(uint16 instance_id)
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout WHERE id=%u", instance_id), errbuf);
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list WHERE id=%u", instance_id), errbuf);
safe_delete_array(query);
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%u", instance_id), errbuf);
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE id=%u", instance_id), errbuf);
safe_delete_array(query);
RunQuery(query, MakeAnyLenString(&query, "DELETE FROM respawn_times WHERE instance_id=%u", instance_id), errbuf);
@ -2354,7 +2354,7 @@ bool Database::CheckInstanceExpired(uint16 instance_id)
int32 start_time = 0;
int32 duration = 0;
uint32 never_expires = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_lockout WHERE id=%u",
if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
instance_id), errbuf, &result))
{
safe_delete_array(query);
@ -2400,7 +2400,7 @@ uint32 Database::ZoneIDFromInstanceID(uint16 instance_id)
MYSQL_ROW row;
uint32 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone FROM instance_lockout where id=%u", instance_id),
if (RunQuery(query, MakeAnyLenString(&query, "SELECT zone FROM instance_list where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
@ -2433,7 +2433,7 @@ uint32 Database::VersionFromInstanceID(uint16 instance_id)
MYSQL_ROW row;
uint32 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id),
if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_list where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
@ -2468,7 +2468,7 @@ uint32 Database::GetTimeRemainingInstance(uint16 instance_id, bool &is_perma)
uint32 duration = 0;
uint32 never_expires = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_lockout WHERE id=%u",
if (RunQuery(query, MakeAnyLenString(&query, "SELECT start_time, duration, never_expires FROM instance_list WHERE id=%u",
instance_id), errbuf, &result))
{
safe_delete_array(query);
@ -2516,68 +2516,29 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT COUNT(*) FROM instance_lockout"), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
row = mysql_fetch_row(result);
int count = atoi(row[0]);
if(count == 0)
{
mysql_free_result(result);
instance_id = RuleI(Zone, ReservedInstances) + 1;
return true;
}
}
else
{
mysql_free_result(result);
}
mysql_free_result(result);
}
else
{
safe_delete_array(query);
instance_id = 0;
return false;
}
uint32 count = RuleI(Zone, ReservedInstances) + 1;
uint32 max = 65535;
int32 count = RuleI(Zone, ReservedInstances) + 1;
int32 max = 65535;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where id >= %i ORDER BY id", count), errbuf, &result))
{
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id >= %i ORDER BY id", count), errbuf, &result)) {
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
{
while((row = mysql_fetch_row(result)))
{
if(count < atoi(row[0]))
{
if (mysql_num_rows(result) != 0) {
while((row = mysql_fetch_row(result))) {
if(count < atoi(row[0])) {
instance_id = count;
mysql_free_result(result);
return true;
}
else if(count > max)
{
} else if(count > max) {
instance_id = 0;
mysql_free_result(result);
return false;
}
else
{
} else {
count++;
}
}
}
else
{
} else {
mysql_free_result(result);
}
}
else
{
} else {
safe_delete_array(query);
}
instance_id = count;
@ -2590,7 +2551,7 @@ bool Database::CreateInstance(uint16 instance_id, uint32 zone_id, uint32 version
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout (id, zone, version, start_time, duration)"
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_list (id, zone, version, start_time, duration)"
" values(%lu, %lu, %lu, UNIX_TIMESTAMP(), %lu)", (unsigned long)instance_id, (unsigned long)zone_id, (unsigned long)version, (unsigned long)duration), errbuf))
{
safe_delete_array(query);
@ -2611,7 +2572,7 @@ void Database::PurgeExpiredInstances()
MYSQL_ROW row;
uint16 id = 0;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_lockout where "
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where "
"(start_time+duration) <= UNIX_TIMESTAMP() and never_expires = 0"), errbuf, &result))
{
safe_delete_array(query);
@ -2638,7 +2599,7 @@ bool Database::AddClientToInstance(uint16 instance_id, uint32 char_id)
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_lockout_player(id, charid) "
if(RunQuery(query, MakeAnyLenString(&query, "INSERT INTO instance_list_player(id, charid) "
"values(%lu, %lu)", (unsigned long)instance_id, (unsigned long)char_id), errbuf))
{
safe_delete_array(query);
@ -2656,7 +2617,7 @@ bool Database::RemoveClientFromInstance(uint16 instance_id, uint32 char_id)
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu AND charid=%lu",
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE id=%lu AND charid=%lu",
(unsigned long)instance_id, (unsigned long)char_id), errbuf))
{
safe_delete_array(query);
@ -2674,7 +2635,7 @@ bool Database::RemoveClientsFromInstance(uint16 instance_id)
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_lockout_player WHERE id=%lu",
if(RunQuery(query, MakeAnyLenString(&query, "DELETE FROM instance_list_player WHERE id=%lu",
(unsigned long)instance_id), errbuf))
{
safe_delete_array(query);
@ -2693,7 +2654,7 @@ bool Database::CheckInstanceExists(uint16 instance_id)
char *query = 0;
MYSQL_RES *result;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM instance_lockout where id=%u", instance_id),
if (RunQuery(query, MakeAnyLenString(&query, "SELECT * FROM instance_list where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
@ -2738,7 +2699,7 @@ uint16 Database::GetInstanceVersion(uint16 instance_id)
MYSQL_ROW row;
uint32 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_lockout where id=%u", instance_id),
if (RunQuery(query, MakeAnyLenString(&query, "SELECT version FROM instance_list where id=%u", instance_id),
errbuf, &result))
{
safe_delete_array(query);
@ -2771,9 +2732,9 @@ uint16 Database::GetInstanceID(const char* zone, uint32 charid, int16 version)
MYSQL_ROW row;
uint16 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
"instance_lockout_player.charid=%u LIMIT 1;", GetZoneID(zone), version, charid, charid), errbuf, &result))
if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_list.id FROM instance_list, instance_list_player "
"WHERE instance_list.zone=%u AND instance_list.version=%u AND instance_list.id=instance_list_player.id AND "
"instance_list_player.charid=%u LIMIT 1;", GetZoneID(zone), version, charid, charid), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
@ -2808,9 +2769,9 @@ uint16 Database::GetInstanceID(uint32 zone, uint32 charid, int16 version)
MYSQL_ROW row;
uint16 ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_lockout.id FROM instance_lockout, instance_lockout_player "
"WHERE instance_lockout.zone=%u AND instance_lockout.version=%u AND instance_lockout.id=instance_lockout_player.id AND "
"instance_lockout_player.charid=%u LIMIT 1;", zone, version, charid), errbuf, &result))
if (RunQuery(query, MakeAnyLenString(&query, "SELECT instance_list.id FROM instance_list, instance_list_player "
"WHERE instance_list.zone=%u AND instance_list.version=%u AND instance_list.id=instance_list_player.id AND "
"instance_list_player.charid=%u LIMIT 1;", zone, version, charid), errbuf, &result))
{
safe_delete_array(query);
if (mysql_num_rows(result) != 0)
@ -2840,7 +2801,7 @@ void Database::GetCharactersInInstance(uint16 instance_id, std::list<uint32> &ch
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_lockout_player WHERE id=%u", instance_id), errbuf, &result)) {
if (RunQuery(query, MakeAnyLenString(&query, "SELECT charid FROM instance_list_player WHERE id=%u", instance_id), errbuf, &result)) {
safe_delete_array(query);
while ((row = mysql_fetch_row(result)))
{
@ -2950,7 +2911,7 @@ void Database::SetInstanceDuration(uint16 instance_id, uint32 new_duration)
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `instance_lockout` SET start_time=UNIX_TIMESTAMP(), "
if(RunQuery(query, MakeAnyLenString(&query, "UPDATE `instance_list` SET start_time=UNIX_TIMESTAMP(), "
"duration=%u WHERE id=%u", new_duration, instance_id), errbuf))
{
safe_delete_array(query);
@ -2970,7 +2931,7 @@ bool Database::GlobalInstance(uint16 instance_id)
MYSQL_ROW row;
bool ret;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT is_global from instance_lockout where id=%u LIMIT 1", instance_id), errbuf, &result))
if (RunQuery(query, MakeAnyLenString(&query, "SELECT is_global from instance_list where id=%u LIMIT 1", instance_id), errbuf, &result))
{
safe_delete_array(query);
row = mysql_fetch_row(result);

View File

@ -333,6 +333,8 @@ RULE_REAL ( Combat, ArcheryBaseDamageBonus, 1) // % Modifier to Base Archery Dam
RULE_REAL ( Combat, ArcheryNPCMultiplier, 1.0) // this is multiplied by the regular dmg to get the archery dmg
RULE_BOOL ( Combat, AssistNoTargetSelf, true) //when assisting a target that does not have a target: true = target self, false = leave target as was before assist (false = live like)
RULE_INT ( Combat, MaxRampageTargets, 3) //max number of people hit with rampage
RULE_INT ( Combat, DefaultRampageTargets, 1) // default number of people to hit with rampage
RULE_BOOL ( Combat, RampageHitsTarget, false) // rampage will hit the target if it still has targets left
RULE_INT ( Combat, MaxFlurryHits, 2) //max number of extra hits from flurry
RULE_INT ( Combat, MonkDamageTableBonus, 5) //% bonus monks get to their damage table calcs
RULE_INT ( Combat, FlyingKickBonus, 25) //% Modifier that this skill gets to str and skill bonuses
@ -355,6 +357,14 @@ RULE_REAL ( Combat, LowPlateChainACSoftcapReturn, 0.23)
RULE_REAL ( Combat, LowChainLeatherACSoftcapReturn, 0.17)
RULE_REAL ( Combat, CasterACSoftcapReturn, 0.06)
RULE_REAL ( Combat, MiscACSoftcapReturn, 0.3)
RULE_BOOL ( Combat, OldACSoftcapRules, false) // use old softcaps
RULE_BOOL ( Combat, UseOldDamageIntervalRules, false) // use old damage formulas for everything
RULE_REAL ( Combat, WarACSoftcapReturn, 0.3448) // new AC returns
RULE_REAL ( Combat, ClrRngMnkBrdACSoftcapReturn, 0.3030)
RULE_REAL ( Combat, PalShdACSoftcapReturn, 0.3226)
RULE_REAL ( Combat, DruNecWizEncMagACSoftcapReturn, 0.2000)
RULE_REAL ( Combat, RogShmBstBerACSoftcapReturn, 0.2500)
RULE_REAL ( Combat, SoftcapFactor, 1.88)
RULE_REAL ( Combat, ACthac0Factor, 0.55)
RULE_REAL ( Combat, ACthac20Factor, 0.55)
RULE_INT ( Combat, HitCapPre20, 40) // live has it capped at 40 for whatever dumb reason... this is mainly for custom servers

View File

@ -1704,11 +1704,13 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].ResistDiff=atoi(row[147]);
sp[tempid].dot_stacking_exempt=atoi(row[148]);
sp[tempid].RecourseLink = atoi(row[150]);
sp[tempid].no_partial_resist = atoi(row[151]) != 0;
sp[tempid].short_buff_box = atoi(row[154]);
sp[tempid].descnum = atoi(row[155]);
sp[tempid].effectdescnum = atoi(row[157]);
sp[tempid].reflectable = atoi(row[161]) != 0;
sp[tempid].bonushate=atoi(row[162]);
sp[tempid].EndurCost=atoi(row[166]);
@ -1736,6 +1738,8 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].powerful_flag=atoi(row[209]);
sp[tempid].CastRestriction = atoi(row[211]);
sp[tempid].AllowRest = atoi(row[212]) != 0;
sp[tempid].NotOutofCombat = atoi(row[213]) != 0;
sp[tempid].NotInCombat = atoi(row[214]) != 0;
sp[tempid].persistdeath = atoi(row[224]) != 0;
sp[tempid].DamageShieldType = 0;
}

View File

@ -387,9 +387,11 @@ bool IsAERainNukeSpell(uint16 spell_id)
bool IsPartialCapableSpell(uint16 spell_id)
{
if (spells[spell_id].no_partial_resist)
return false;
if (IsPureNukeSpell(spell_id) || IsFearSpell(spell_id) ||
IsEffectInSpell(spell_id, SE_Root) ||
IsEffectInSpell(spell_id, SE_Charm))
IsEffectInSpell(spell_id, SE_Root))
return true;
return false;
@ -672,6 +674,20 @@ bool IsDiscipline(uint16 spell_id)
return false;
}
bool IsCombatSkill(uint16 spell_id)
{
if (!IsValidSpell(spell_id))
return false;
//Check if Discipline OR melee proc (from non-castable spell)
if ((spells[spell_id].mana == 0 &&
(spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep)) ||
((spells[spell_id].cast_time == 0) && (spells[spell_id].recast_time == 0) && (spells[spell_id].recovery_time == 0)))
return true;
return false;
}
bool IsResurrectionEffects(uint16 spell_id)
{
// spell id 756 is Resurrection Effects spell
@ -932,7 +948,7 @@ bool IsDebuffSpell(uint16 spell_id)
if (IsBeneficialSpell(spell_id) || IsEffectHitpointsSpell(spell_id) || IsStunSpell(spell_id) ||
IsMezSpell(spell_id) || IsCharmSpell(spell_id) || IsSlowSpell(spell_id) ||
IsEffectInSpell(spell_id, SE_Root) || IsEffectInSpell(spell_id, SE_CancelMagic) ||
IsEffectInSpell(spell_id, SE_MovementSpeed) || IsFearSpell(spell_id) || IsEffectInSpell(spell_id, SE_Calm))
IsEffectInSpell(spell_id, SE_MovementSpeed) || IsFearSpell(spell_id) || IsEffectInSpell(spell_id, SE_InstantHate))
return false;
else
return true;

View File

@ -148,7 +148,7 @@ typedef enum {
// full listing: https://forums.station.sony.com/eq/index.php?threads/enumerated-spa-list.206288/
// mirror: http://pastebin.com/MYeQqGwe
#define SE_CurrentHP 0 // implemented - Heals and nukes, repeates every tic if in a buff
#define SE_ArmorClass 1 // implemented
#define SE_ArmorClass 1 // implemented
#define SE_ATK 2 // implemented
#define SE_MovementSpeed 3 // implemented - SoW, SoC, etc
#define SE_STR 4 // implemented
@ -239,7 +239,7 @@ typedef enum {
#define SE_ModelSize 89 // implemented - Shrink, Growth
#define SE_Cloak 90 // *not implemented - Used in only 2 spells
#define SE_SummonCorpse 91 // implemented
#define SE_Calm 92 // implemented - Hate modifier stuff(poorly named)
#define SE_InstantHate 92 // implemented - add hate
#define SE_StopRain 93 // implemented - Wake of Karana
#define SE_NegateIfCombat 94 // *not implemented? - Works client side but there is comment todo in spell effects...Component of Spirit of Scale
#define SE_Sacrifice 95 // implemented
@ -265,7 +265,7 @@ typedef enum {
#define SE_Hunger 115 // implemented - Song of Sustenance
#define SE_CurseCounter 116 // implemented
#define SE_MagicWeapon 117 // implemented - makes weapon magical
#define SE_SingingSkill 118 // *implemented - needs AA conversion
#define SE_Amplification 118 // implemented - Harmonize/Amplification (stacks with other singing mods)
#define SE_AttackSpeed3 119 // implemented
#define SE_HealRate 120 // implemented - reduces healing by a %
#define SE_ReverseDS 121 // implemented
@ -293,7 +293,7 @@ typedef enum {
#define SE_LimitCastTimeMin 143 // implemented
#define SE_LimitCastTimeMax 144 // implemented (*not used in any known live spell)
#define SE_Teleport2 145 // implemented - Banishment of the Pantheon
#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233)
//#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233)
#define SE_PercentalHeal 147 // implemented
#define SE_StackingCommand_Block 148 // implemented?
#define SE_StackingCommand_Overwrite 149 // implemented?
@ -349,73 +349,73 @@ typedef enum {
#define SE_Taunt 199 // implemented - % chance to taunt the target
#define SE_ProcChance 200 // implemented
#define SE_RangedProc 201 // implemented
#define SE_IllusionOther 202 // *not implemented as bonus(Project Illusion)
#define SE_MassGroupBuff 203 // *not implemented as bonus
//#define SE_IllusionOther 202 // *not implemented as bonus(Project Illusion)
//#define SE_MassGroupBuff 203 // *not implemented as bonus
#define SE_GroupFearImmunity 204 // *not implemented as bonus
#define SE_Rampage 205 // implemented
#define SE_AETaunt 206 // implemented
#define SE_FleshToBone 207 // implemented
//#define SE_PurgePoison 208 // not used
#define SE_DispelBeneficial 209 // implemented
#define SE_PetShield 210 // *not implemented
//#define SE_PetShield 210 // *not implemented
#define SE_AEMelee 211 // implemented
#define SE_CastingSkills 212 // *not implemented -Include/Exclude Casting Skill type. (*no longer used on live)
//#define SE_CastingSkills 212 // *not implemented -Include/Exclude Casting Skill type. (*no longer used on live)
#define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet
#define SE_MaxHPChange 214 // implemented
#define SE_PetAvoidance 215 // implemented[AA] - increases pet ability to avoid melee damage
#define SE_Accuracy 216 // implemented
#define SE_HeadShot 217 // not implemented as bonus - ability to head shot (base2 = damage)
//#define SE_HeadShot 217 // not implemented as bonus - ability to head shot (base2 = damage)
#define SE_PetCriticalHit 218 // implemented[AA] - gives pets a baseline critical hit chance
#define SE_SlayUndead 219 // implemented - Allow extra damage against undead (base1 = rate, base2 = damage mod).
#define SE_SkillDamageAmount 220 // implemented
#define SE_Packrat 221 // not implemented as bonus
#define SE_Packrat 221 // implemented as bonus
#define SE_BlockBehind 222 // implemented - Chance to block from behind (with our without Shield)
//#define SE_DoubleRiposte 223 // not used
#define SE_GiveDoubleRiposte 224 // implemented[AA]
#define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance.
#define SE_TwoHandBash 226 // not implemented as bonus
#define SE_TwoHandBash 226 // *not implemented as bonus
#define SE_ReduceSkillTimer 227 // implemented
#define SE_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 // *not implemented - (Crown of Feathers) Increase metabolism?
#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison
//#define SE_Metabolism 233 // *not implemented - (Crown of Feathers) Increase metabolism?
//#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 // *not 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_IllusionPersistence 238 // *not 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_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 // not implemented as bonus - 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_SetBreathLevel 246 // not implemented as bonus
//#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 sympathetic proc by %
#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 // implemented - lets you raise more than one tradeskill above master.
#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect
//#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect
#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
@ -428,11 +428,11 @@ 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].
@ -453,13 +453,13 @@ typedef enum {
#define SE_FcDamageAmtCrit 303 // implemented - adds direct spell damage
#define SE_OffhandRiposteFail 304 // implemented as bonus - enemy cannot riposte offhand attacks
#define SE_MitigateDamageShield 305 // implemented - off hand attacks only (Shielding Resistance)
#define SE_ArmyOfTheDead 306 // *not implemented NecroAA - This ability calls up to five shades of nearby corpses back to life to serve the necromancer. The soulless abominations will mindlessly fight the target until called back to the afterlife some time later. The first rank summons up to three shades that serve for 60 seconds, and each additional rank adds one more possible shade and increases their duration by 15 seconds
#define SE_Appraisal 307 // *not implemented Rogue AA - This ability allows you to estimate the selling price of an item you are holding on your cursor.
//#define SE_ArmyOfTheDead 306 // *not implemented NecroAA - This ability calls up to five shades of nearby corpses back to life to serve the necromancer. The soulless abominations will mindlessly fight the target until called back to the afterlife some time later. The first rank summons up to three shades that serve for 60 seconds, and each additional rank adds one more possible shade and increases their duration by 15 seconds
//#define SE_Appraisal 307 // *not implemented Rogue AA - This ability allows you to estimate the selling price of an item you are holding on your cursor.
#define SE_SuspendMinion 308 // not implemented as bonus
#define SE_YetAnotherGate 309 // implemented
#define SE_ReduceReuseTimer 310 // implemented
#define SE_LimitCombatSkills 311 // implemented - Excludes focus from procs (except if proc is a memorizable spell)
#define SE_Sanctuary 312 // *not implemented
//#define SE_Sanctuary 312 // *not implemented
#define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items
#define SE_Invisibility2 314 // implemented - fixed duration invisible
#define SE_InvisVsUndead2 315 // implemented - fixed duration ITU
@ -472,14 +472,14 @@ typedef enum {
#define SE_GateToHomeCity 322 // implemented
#define SE_DefensiveProc 323 // implemented
#define SE_HPToMana 324 // implemented
#define SE_ChanceInvsBreakToAoE 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell.
#define SE_SpellSlotIncrease 326 // not implemented as bonus - increases your spell slot availability
//#define SE_ChanceInvsBreakToAoE 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell.
#define SE_SpellSlotIncrease 326 // *not implemented as bonus - increases your spell slot availability
#define SE_MysticalAttune 327 // implemented - increases amount of buffs that a player can have
#define SE_DelayDeath 328 // implemented - increases how far you can fall below 0 hp before you die
#define SE_ManaAbsorbPercentDamage 329 // implemented
#define SE_CriticalDamageMob 330 // implemented
#define SE_Salvage 331 // *not implemented - chance to recover items that would be destroyed in failed tradeskill combine
#define SE_SummonToCorpse 332 // *not implemented AA - Call of the Wild (Druid/Shaman Res spell with no exp)
#define SE_Salvage 331 // implemented - chance to recover items that would be destroyed in failed tradeskill combine
//#define SE_SummonToCorpse 332 // *not implemented AA - Call of the Wild (Druid/Shaman Res spell with no exp)
#define SE_EffectOnFade 333 // implemented
#define SE_BardAEDot 334 // implemented
#define SE_BlockNextSpellFocus 335 // implemented - base1 chance to block next spell ie Puratus (8494)
@ -492,15 +492,15 @@ typedef enum {
#define SE_ImmuneFleeing 342 // implemented - stop mob from fleeing
#define SE_InterruptCasting 343 // implemented - % chance to interrupt spells being cast every tic. Cacophony (8272)
#define SE_ChannelChanceItems 344 // implemented[AA] - chance to not have ITEM effects interrupted when you take damage.
#define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill
#define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill
//#define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill
//#define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill
#define SE_DoubleRangedAttack 347 // implemented - chance at an additional archery attack (consumes arrow)
#define SE_LimitManaMin 348 // implemented
#define SE_ShieldEquipHateMod 349 // implemented[AA] Increase melee hate when wearing a shield.
#define SE_ManaBurn 350 // implemented - Drains mana for damage/heal at a defined ratio up to a defined maximum amount of mana.
#define SE_PersistentEffect 351 // *not implemented. creates a trap/totem that casts a spell (spell id + base1?) when anything comes near it. can probably make a beacon for this
#define SE_IncreaseTrapCount 352 // *not implemented - looks to be some type of invulnerability? Test ITC (8755)
#define SE_AdditionalAura 353 // *not implemented - allows use of more than 1 aura, aa effect
//#define SE_PersistentEffect 351 // *not implemented. creates a trap/totem that casts a spell (spell id + base1?) when anything comes near it. can probably make a beacon for this
//#define SE_IncreaseTrapCount 352 // *not implemented - looks to be some type of invulnerability? Test ITC (8755)
//#define SE_AdditionalAura 353 // *not implemented - allows use of more than 1 aura, aa effect
//#define SE_DeactivateAllTraps 354 // *not implemented - looks to be some type of invulnerability? Test DAT (8757)
//#define SE_LearnTrap 355 // *not implemented - looks to be some type of invulnerability? Test LT (8758)
//#define SE_ChangeTriggerType 356 // not used
@ -509,17 +509,17 @@ typedef enum {
#define SE_Invulnerabilty 359 // *not implemented - Invulnerability (Brell's Blessing)
#define SE_SpellOnKill 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_SpellOnKill2 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin)
#define SE_ShieldEquipDmgMod 366 // implemented[AA] Damage modifier to melee if shield equiped. (base1 = dmg mod , base2 = ?) ie Shield Specialist AA
#define SE_SetBodyType 367 // implemented - set body type of base1 so it can be affected by spells that are limited to that type (Plant, Animal, Undead, etc)
#define SE_FactionMod 368 // *not implemented - increases faction with base1 (faction id, live won't match up w/ ours) by base2
//#define SE_FactionMod 368 // *not implemented - increases faction with base1 (faction id, live won't match up w/ ours) by base2
#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_CastOnWearoff 373 // implemented - Triggers only if fades after natural duration.
#define SE_ApplyEffect 374 // implemented
#define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount
@ -528,30 +528,30 @@ typedef enum {
#define SE_SpellEffectResistChance 378 // implemented - Increase chance to resist specific spell effect (base1=value, base2=spell effect id)
#define SE_ShadowStepDirectional 379 // implemented - handled by client
#define SE_Knockdown 380 // implemented - small knock back(handled by client)
#define SE_KnockTowardCaster 381 // *not implemented (Call of Hither) knocks you back to caster (value) distance units infront
//#define SE_KnockTowardCaster 381 // *not implemented (Call of Hither) knocks you back to caster (value) distance units infront
#define SE_NegateSpellEffect 382 // implemented - negates specific spell bonuses for duration of the debuff.
#define SE_SympatheticProc 383 // implemented - focus on items that has chance to proc a spell when you cast
#define SE_Leap 384 // implemented - Leap effect, ie stomping leap
#define SE_LimitSpellGroup 385 // implemented - Limits to spell group(ie type 3 reuse reduction augs that are class specific and thus all share s SG)
#define SE_CastOnCurer 386 // implemented - Casts a spell on the person curing
#define SE_CastOnCure 387 // implemented - Casts a spell on the cured person
#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA)
//#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA)
#define SE_FcTimerRefresh 389 // implemented - Refresh spell icons
#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited.
//#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited.
#define SE_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.
#define SE_FcHealPctCritIncoming 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited]
#define SE_FcHealAmtCrit 396 // implemented - Adds a direct healing amount to spells
#define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets.
//#define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets.
#define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets
#define SE_FcTwincast 399 // implemented - cast 2 spells for every 1
#define SE_HealGroupFromMana 400 // implemented - Drains mana and heals for each point of mana drained
#define SE_ManaDrainWithDmg 401 // implemented - Deals damage based on the amount of mana drained
#define SE_EndDrainWithDmg 402 // implemented - Deals damage for the amount of endurance drained
#define SE_LimitSpellClass 403 // *not implemented - unclear what this refers too (not 'right click' spell bar)
#define SE_LimitSpellSubclass 404 // *not implemented - unclear what this refers too (not 'right click' spell bar)
//#define SE_LimitSpellClass 403 // *not implemented - unclear what this refers too (not 'right click' spell bar)
//#define SE_LimitSpellSubclass 404 // *not implemented - unclear what this refers too (not 'right click' spell bar)
#define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block)
#define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted
#define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied)
@ -572,8 +572,8 @@ typedef enum {
#define SE_LimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above)
#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_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_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_SkillProc2 429 // implemented - chance to proc when using a skill (most have hit limits)
@ -584,20 +584,20 @@ typedef enum {
#define SE_CriticalHealDecay 434 // implemented - increase critical heal chance, effect decays based on level of spell it effects.
#define SE_CriticalRegenDecay 435 // implemented - increase critical heal over time chance, effect decays based on level of spell it effects.
//#define SE_BeneficialCountDownHold 436 // not used ( 23491 | ABTest Buff Hold)
#define SE_TeleporttoAnchor 437 // *not implemented - Teleport Guild Hall Anchor(33099)
#define SE_TranslocatetoAnchor 438 // *not implemented - Translocate Primary Anchor (27750)
#define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination
//#define SE_TeleporttoAnchor 437 // *not implemented - Teleport Guild Hall Anchor(33099)
//#define SE_TranslocatetoAnchor 438 // *not implemented - Translocate Primary Anchor (27750)
//#define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination
#define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC
#define SE_CancleIfMoved 441 // *not implemented - Buff is removed from target when target moves X amount of distance away from where initially hit.
#define SE_TriggerOnValueAmount 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist)
#define SE_TriggerIfMovement 443 // *not implemented - Trigger a spell if you move (37846 | Chopping Block)
#define SE_ImprovedTaunt 444 // *not implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% up to level Z
#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs.
#define SE_DistanceRemoval 441 // implemented - Buff is removed from target when target moves X amount of distance away from where initially hit.
#define SE_TriggerOnReqTarget 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist)
#define SE_TriggerOnReqCaster 443 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist)
#define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y
//#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs.
//#define SE_AStacker 446 // *not implementet - bufff stacking blocker ? (26219 | Qirik's Watch)
//#define SE_BStacker 447 // *not implemented
//#define SE_CStacker 448 // *not implemented
//#define SE_DStacker 449 // *not implemented
//#define SE_DotGuard 450 // *not implemented
#define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value
#define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage
#define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage
#define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken
@ -680,15 +680,18 @@ struct SPDat_Spell_Struct
/* 148 */ int8 dot_stacking_exempt; // If 1 doesn't stack with self cast by others. If -1 (not implemented) doesn't stack with same effect (???)
/* 149 */ //int deletable;
/* 150 */ uint16 RecourseLink;
/* 151 */ // 151: -1, 0, or 1
/* 151 */ bool no_partial_resist; // 151: -1, 0, or 1
// 152 & 153: all set to 0
/* 154 */ int8 short_buff_box; // != 0, goes to short buff box.
/* 155 */ int descnum; // eqstr of description of spell
/* 156 */ //int typedescnum; // eqstr of type description
/* 157 */ int effectdescnum; // eqstr of effect description
/* 158 */
/* 158 */ //Category Desc ID 3
/* 159 */ //bool npc_no_los;
/* 161 */ bool reflectable;
/* 162 */ int bonushate;
/* 163 */
/* 164 */ // for most spells this appears to mimic ResistDiff
/* 166 */ int EndurCost;
/* 167 */ int8 EndurTimerIndex;
/* 168 */ //int IsDisciplineBuff; //Will goto the combat window when cast
@ -709,8 +712,8 @@ struct SPDat_Spell_Struct
/* 191 */ uint8 viral_targets;
/* 192 */ uint8 viral_timer;
/* 193 */ int NimbusEffect;
/* 194 */ float directional_start;
/* 195 */ float directional_end;
/* 194 */ float directional_start; //Cone Start Angle:
/* 195 */ float directional_end; // Cone End Angle:
/* 196 */
/* 197 */ bool not_extendable;
/* 198- 199 */
@ -719,12 +722,14 @@ struct SPDat_Spell_Struct
/* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented)
/* 204 - 206 */
/* 207 */ int spellgroup;
/* 208 */
/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though
/* 210 */
/* 208 */ // int rank - increments AA effects with same name
/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though
/* 210 */ // bool DurationFrozen; ???
/* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat
/* 212 */ bool AllowRest;
/* 213 - 218 */
/* 213 */ bool NotOutofCombat; //Fail if cast out of combat
/* 214 */ bool NotInCombat; //Fail if cast in combat
/* 215 - 218 */
/* 219 */ //int maxtargets; // is used for beam and ring spells for target # limits (not implemented)
/* 220 - 223 */
/* 224 */ bool persistdeath; // buff doesn't get stripped on death
@ -795,6 +800,7 @@ int32 CalculateCorruptionCounters(uint16 spell_id);
int32 CalculateCounters(uint16 spell_id);
bool IsDisciplineBuff(uint16 spell_id);
bool IsDiscipline(uint16 spell_id);
bool IsCombatSkill(uint16 spell_id);
bool IsResurrectionEffects(uint16 spell_id);
bool IsRuneSpell(uint16 spell_id);
bool IsMagicRuneSpell(uint16 spell_id);

View File

@ -9,5 +9,6 @@ CREATE TABLE IF NOT EXISTS tblWorldServerRegistration (
ServerLastIPAddr varchar(15) NULL,
ServerAdminID integer NOT NULL,
Note varchar(300) NULL,
ServerTrusted int(11),
PRIMARY KEY (ServerID, ServerLongName)
) ENGINE=InnoDB;

View File

@ -0,0 +1,3 @@
-- rename the instance_lockout tables to instance_list. They have nothing to do with lockouts.
ALTER TABLE `instance_lockout` RENAME TO `instance_list` ;
ALTER TABLE `instance_lockout_player` RENAME TO `instance_list_player` ;

View File

@ -0,0 +1,17 @@
ALTER TABLE `spells_new` CHANGE `field161` `not_reflectable` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field151` `no_partial_resist` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field189` `MinResist` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field190` `MaxResist` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field194` `ConeStartAngle` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field195` `ConeStopAngle` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field208` `rank` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field159` `npc_no_los` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field213` `NotOutofCombat` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field214` `NotInCombat` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field168` `IsDiscipline` INT(11) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `field211` `CastRestriction` INT(11) NOT NULL DEFAULT '0';
UPDATE altadv_vars SET sof_next_id = 8261 WHERE skill_id = 8232;
UPDATE altadv_vars SET sof_next_id = 0 WHERE skill_id = 8261;
UPDATE altadv_vars SET sof_current_level = 3 WHERE skill_id = 8261;

View File

@ -0,0 +1,22 @@
-- UPDATE BUFF TABLES
ALTER TABLE `character_buffs` CHANGE `death_save_chance` `dot_rune` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `merc_buffs` CHANGE `DeathSaveSuccessChance` `dot_rune` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `botbuffs` CHANGE `DeathSaveSuccessChance` `dot_rune` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `character_buffs` CHANGE `death_save_aa_chance` `caston_x` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `merc_buffs` CHANGE `CasterAARank` `caston_x` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `botbuffs` CHANGE `CasterAARank` `caston_x` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `character_buffs` ADD `caston_y` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `merc_buffs` ADD `caston_y` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `botbuffs` ADD `caston_y` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `character_buffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `merc_buffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `botbuffs` ADD `caston_z` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `character_buffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `merc_buffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `botbuffs` ADD `ExtraDIChance` INT(10) NOT NULL DEFAULT '0';
ALTER TABLE `spells_new` CHANGE `not_reflectable` `reflectable` INT(11) NOT NULL DEFAULT '0';

View File

@ -1054,7 +1054,8 @@ void Mob::AI_Process() {
SetTarget(hate_list.GetTop(this));
}
} else {
SetTarget(hate_list.GetTop(this));
if (!ImprovedTaunt())
SetTarget(hate_list.GetTop(this));
}
}
@ -1141,30 +1142,26 @@ void Mob::AI_Process() {
Attack(target, 13);
}
if (target)
{
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 = MakeRandomInt(0, 99);
if (CanThisClassDoubleAttack()
//check double attack, this is NOT the same rules that clients use...
&& RandRoll < (GetLevel() + NPCDualAttackModifier))
{
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, 13);
// lets see if we can do a triple attack with the main hand
//pets are excluded from triple and quads...
if (GetSpecialAbility(SPECATK_TRIPLE)
&& !IsPet() && RandRoll < (GetLevel()+NPCTripleAttackModifier))
{
if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD))
&& !IsPet() && RandRoll < (GetLevel() + NPCTripleAttackModifier)) {
Attack(target, 13);
// now lets check the quad attack
if (GetSpecialAbility(SPECATK_QUAD)
&& RandRoll < (GetLevel() + NPCQuadAttackModifier))
{
&& RandRoll < (GetLevel() + NPCQuadAttackModifier)) {
Attack(target, 13);
}
}
}
}
@ -1173,48 +1170,41 @@ void Mob::AI_Process() {
int flurry_chance = GetSpecialAbilityParam(SPECATK_FLURRY, 0);
flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance);
ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2);
if(cur > 0) {
opts.damage_percent = cur / 100.0f;
}
if (MakeRandomInt(0, 99) < flurry_chance) {
ExtraAttackOptions opts;
int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2);
if (cur > 0)
opts.damage_percent = cur / 100.0f;
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3);
if(cur > 0) {
opts.damage_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3);
if (cur > 0)
opts.damage_flat = cur;
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4);
if(cur > 0) {
opts.armor_pen_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4);
if (cur > 0)
opts.armor_pen_percent = cur / 100.0f;
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5);
if(cur > 0) {
opts.armor_pen_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5);
if (cur > 0)
opts.armor_pen_flat = cur;
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6);
if(cur > 0) {
opts.crit_percent = cur / 100.0f;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6);
if (cur > 0)
opts.crit_percent = cur / 100.0f;
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 7);
if(cur > 0) {
opts.crit_flat = cur;
}
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 7);
if (cur > 0)
opts.crit_flat = cur;
if (MakeRandomInt(0, 99) < flurry_chance)
Flurry(&opts);
}
}
if (IsPet()) {
Mob *owner = GetOwner();
if (owner){
int16 flurry_chance = owner->aabonuses.PetFlurry + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry;
if (owner) {
int16 flurry_chance = owner->aabonuses.PetFlurry +
owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry;
if (flurry_chance && (MakeRandomInt(0, 99) < flurry_chance))
Flurry(nullptr);
}
@ -1294,7 +1284,7 @@ void Mob::AI_Process() {
if(cur > 0) {
opts.crit_flat = cur;
}
AreaRampage(&opts);
}
}
@ -1997,59 +1987,57 @@ bool Mob::Flurry(ExtraAttackOptions *opts)
bool Mob::AddRampage(Mob *mob)
{
if(!mob)
if (!mob)
return false;
if (!GetSpecialAbility(SPECATK_RAMPAGE))
return false;
for (int i = 0; i < RampageArray.size(); i++)
{
// if name is already on the list dont add it again
if (strcasecmp(mob->GetName(), RampageArray[i].c_str()) == 0)
for (int i = 0; i < RampageArray.size(); i++) {
// if Entity ID is already on the list don't add it again
if (mob->GetID() == RampageArray[i])
return false;
}
std::string r_name = mob->GetName();
RampageArray.push_back(r_name);
RampageArray.push_back(mob->GetID());
return true;
}
void Mob::ClearRampage(){
void Mob::ClearRampage()
{
RampageArray.clear();
}
bool Mob::Rampage(ExtraAttackOptions *opts)
{
int index_hit = 0;
if (!IsPet()) {
if (!IsPet())
entity_list.MessageClose_StringID(this, true, 200, MT_NPCRampage, NPC_RAMPAGE, GetCleanName());
} else {
else
entity_list.MessageClose_StringID(this, true, 200, MT_PetFlurry, NPC_RAMPAGE, GetCleanName());
}
int rampage_targets = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1);
rampage_targets = rampage_targets > 0 ? rampage_targets : RuleI(Combat, MaxRampageTargets);
for (int i = 0; i < RampageArray.size(); i++)
{
if(index_hit >= rampage_targets)
if (rampage_targets == 0) // if set to 0 or not set in the DB
rampage_targets = RuleI(Combat, DefaultRampageTargets);
if (rampage_targets > RuleI(Combat, MaxRampageTargets))
rampage_targets = RuleI(Combat, MaxRampageTargets);
for (int i = 0; i < RampageArray.size(); i++) {
if (index_hit >= rampage_targets)
break;
// range is important
Mob *m_target = entity_list.GetMob(RampageArray[i].c_str());
if(m_target)
{
if(m_target == GetTarget())
Mob *m_target = entity_list.GetMob(RampageArray[i]);
if (m_target) {
if (m_target == GetTarget())
continue;
if (CombatRange(m_target))
{
if (CombatRange(m_target)) {
Attack(m_target, 13, false, false, false, opts);
index_hit++;
}
}
}
if(index_hit < rampage_targets) {
if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets)
Attack(GetTarget(), 13, false, false, false, opts);
}
return true;
}

View File

@ -46,6 +46,12 @@ void QuestParserCollection::RegisterQuestInterface(QuestInterface *qi, std::stri
_load_precedence.push_back(qi);
}
void QuestParserCollection::ClearInterfaces() {
_interfaces.clear();
_extensions.clear();
_load_precedence.clear();
}
void QuestParserCollection::AddVar(std::string name, std::string val) {
std::list<QuestInterface*>::iterator iter = _load_precedence.begin();
while(iter != _load_precedence.end()) {

View File

@ -39,7 +39,8 @@ public:
~QuestParserCollection();
void RegisterQuestInterface(QuestInterface *qi, std::string ext);
void UnRegisterQuestInterface(QuestInterface *qi, std::string ext);
void ClearInterfaces();
void AddVar(std::string name, std::string val);
void Init();
void ReloadQuests(bool reset_timers = true);

View File

@ -1257,7 +1257,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
break;
}
case SE_ReduceHate:
case SE_Calm: {
case SE_InstantHate: {
nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
break;
}
@ -1282,9 +1282,6 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
if (IsClient())
HateMod += CastToClient()->GetFocusEffect(focusSpellHateMod, spell_id);
//Live AA - Spell casting subtlety
HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod;
AggroAmount = (AggroAmount * HateMod) / 100;
//made up number probably scales a bit differently on live but it seems like it will be close enough
@ -1405,7 +1402,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
return true;
//1: The mob has a default 25% chance of being allowed a resistance check against the charm.
if (MakeRandomInt(0, 100) > RuleI(Spells, CharmBreakCheckChance))
if (MakeRandomInt(0, 99) > RuleI(Spells, CharmBreakCheckChance))
return true;
//2: The mob makes a resistance check against the charm
@ -1419,7 +1416,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
//3: At maxed ability, Total Domination has a 50% chance of preventing the charm break that otherwise would have occurred.
uint16 TotalDominationBonus = caster->aabonuses.CharmBreakChance + caster->spellbonuses.CharmBreakChance + caster->itembonuses.CharmBreakChance;
if (MakeRandomInt(0, 100) < TotalDominationBonus)
if (MakeRandomInt(0, 99) < TotalDominationBonus)
return true;
}

View File

@ -199,11 +199,6 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
if(IsClient() && other->IsClient())
pvpmode = true;
CheckNumHitsRemaining(1);
if (attacker)
attacker->CheckNumHitsRemaining(2);
if (chance_mod >= 10000)
return true;
@ -541,17 +536,16 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts)
{
if(damage <= 0)
if (damage <= 0)
return;
Mob* defender = this;
float aa_mit = 0;
float aa_mit = (aabonuses.CombatStability + itembonuses.CombatStability +
spellbonuses.CombatStability) / 100.0f;
aa_mit = (aabonuses.CombatStability + itembonuses.CombatStability + spellbonuses.CombatStability)/100.0f;
if(RuleB(Combat, UseIntervalAC))
{
float softcap = 0.0;
if (RuleB(Combat, UseIntervalAC)) {
float softcap = (GetSkill(SkillDefense) + GetLevel()) *
RuleR(Combat, SoftcapFactor) * (1.0 + aa_mit);
float mitigation_rating = 0.0;
float attack_rating = 0.0;
int shield_ac = 0;
@ -561,150 +555,101 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac
float monkweight = RuleI(Combat, MonkACBonusWeight);
monkweight = mod_monk_weight(monkweight, attacker);
if(IsClient())
{
if (IsClient()) {
armor = CastToClient()->GetRawACNoShield(shield_ac);
weight = (CastToClient()->CalcCurrentWeight() / 10.0);
}
else if(IsNPC())
{
} else if (IsNPC()) {
armor = CastToNPC()->GetRawAC();
if(!IsPet())
{
if (!IsPet())
armor = (armor / RuleR(Combat, NPCACFactor));
}
armor += spellbonuses.AC + itembonuses.AC + 1;
}
if(opts) {
if (opts) {
armor *= (1.0f - opts->armor_pen_percent);
armor -= opts->armor_pen_flat;
}
if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER)
{
softcap = RuleI(Combat, ClothACSoftcap);
}
else if(GetClass() == MONK && weight <= monkweight)
{
softcap = RuleI(Combat, MonkACSoftcap);
}
else if(GetClass() == DRUID || GetClass() == BEASTLORD || GetClass() == MONK)
{
softcap = RuleI(Combat, LeatherACSoftcap);
}
else if(GetClass() == SHAMAN || GetClass() == ROGUE || GetClass() == BERSERKER || GetClass() == RANGER)
{
softcap = RuleI(Combat, ChainACSoftcap);
}
else
{
softcap = RuleI(Combat, PlateACSoftcap);
if (RuleB(Combat, OldACSoftcapRules)) {
if (GetClass() == WIZARD || GetClass() == MAGICIAN ||
GetClass() == NECROMANCER || GetClass() == ENCHANTER)
softcap = RuleI(Combat, ClothACSoftcap);
else if (GetClass() == MONK && weight <= monkweight)
softcap = RuleI(Combat, MonkACSoftcap);
else if(GetClass() == DRUID || GetClass() == BEASTLORD || GetClass() == MONK)
softcap = RuleI(Combat, LeatherACSoftcap);
else if(GetClass() == SHAMAN || GetClass() == ROGUE ||
GetClass() == BERSERKER || GetClass() == RANGER)
softcap = RuleI(Combat, ChainACSoftcap);
else
softcap = RuleI(Combat, PlateACSoftcap);
}
softcap += shield_ac;
armor += shield_ac;
softcap += (softcap * (aa_mit * RuleR(Combat, AAMitigationACFactor)));
if(armor > softcap)
{
if (RuleB(Combat, OldACSoftcapRules))
softcap += (softcap * (aa_mit * RuleR(Combat, AAMitigationACFactor)));
if (armor > softcap) {
int softcap_armor = armor - softcap;
if(GetClass() == WARRIOR)
{
softcap_armor = softcap_armor * RuleR(Combat, WarriorACSoftcapReturn);
}
else if(GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || (GetClass() == MONK && weight <= monkweight))
{
softcap_armor = softcap_armor * RuleR(Combat, KnightACSoftcapReturn);
}
else if(GetClass() == CLERIC || GetClass() == BARD || GetClass() == BERSERKER || GetClass() == ROGUE || GetClass() == SHAMAN || GetClass() == MONK)
{
softcap_armor = softcap_armor * RuleR(Combat, LowPlateChainACSoftcapReturn);
}
else if(GetClass() == RANGER || GetClass() == BEASTLORD)
{
softcap_armor = softcap_armor * RuleR(Combat, LowChainLeatherACSoftcapReturn);
}
else if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER || GetClass() == DRUID)
{
softcap_armor = softcap_armor * RuleR(Combat, CasterACSoftcapReturn);
}
else
{
softcap_armor = softcap_armor * RuleR(Combat, MiscACSoftcapReturn);
if (RuleB(Combat, OldACSoftcapRules)) {
if (GetClass() == WARRIOR)
softcap_armor = softcap_armor * RuleR(Combat, WarriorACSoftcapReturn);
else if (GetClass() == SHADOWKNIGHT || GetClass() == PALADIN ||
(GetClass() == MONK && weight <= monkweight))
softcap_armor = softcap_armor * RuleR(Combat, KnightACSoftcapReturn);
else if (GetClass() == CLERIC || GetClass() == BARD ||
GetClass() == BERSERKER || GetClass() == ROGUE ||
GetClass() == SHAMAN || GetClass() == MONK)
softcap_armor = softcap_armor * RuleR(Combat, LowPlateChainACSoftcapReturn);
else if (GetClass() == RANGER || GetClass() == BEASTLORD)
softcap_armor = softcap_armor * RuleR(Combat, LowChainLeatherACSoftcapReturn);
else if (GetClass() == WIZARD || GetClass() == MAGICIAN ||
GetClass() == NECROMANCER || GetClass() == ENCHANTER ||
GetClass() == DRUID)
softcap_armor = softcap_armor * RuleR(Combat, CasterACSoftcapReturn);
else
softcap_armor = softcap_armor * RuleR(Combat, MiscACSoftcapReturn);
} else {
if (GetClass() == WARRIOR)
softcap_armor *= RuleR(Combat, WarACSoftcapReturn);
else if (GetClass() == PALADIN || GetClass() == SHADOWKNIGHT)
softcap_armor *= RuleR(Combat, PalShdACSoftcapReturn);
else if (GetClass() == CLERIC || GetClass() == RANGER ||
GetClass() == MONK || GetClass() == BARD)
softcap_armor *= RuleR(Combat, ClrRngMnkBrdACSoftcapReturn);
else if (GetClass() == DRUID || GetClass() == NECROMANCER ||
GetClass() == WIZARD || GetClass() == ENCHANTER ||
GetClass() == MAGICIAN)
softcap_armor *= RuleR(Combat, DruNecWizEncMagACSoftcapReturn);
else if (GetClass() == ROGUE || GetClass() == SHAMAN ||
GetClass() == BEASTLORD || GetClass() == BERSERKER)
softcap_armor *= RuleR(Combat, RogShmBstBerACSoftcapReturn);
else
softcap_armor *= RuleR(Combat, MiscACSoftcapReturn);
}
armor = softcap + softcap_armor;
}
mitigation_rating = 0.0;
if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER)
{
if (GetClass() == WIZARD || GetClass() == MAGICIAN ||
GetClass() == NECROMANCER || GetClass() == ENCHANTER)
mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 4.0) + armor + 1;
}
else
{
mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 3.0) + (armor * 1.333333) + 1;
}
mitigation_rating *= 0.847;
mitigation_rating = mod_mitigation_rating(mitigation_rating, attacker);
if(attacker->IsClient())
{
if (attacker->IsClient())
attack_rating = (attacker->CastToClient()->CalcATK() + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345));
}
else
{
attack_rating = (attacker->GetATK() + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9));
}
attack_rating = attacker->mod_attack_rating(attack_rating, this);
float d = 10.0;
float mit_roll = MakeRandomFloat(0, mitigation_rating);
float atk_roll = MakeRandomFloat(0, attack_rating);
if(atk_roll > mit_roll)
{
float a_diff = (atk_roll - mit_roll);
float thac0 = attack_rating * RuleR(Combat, ACthac0Factor);
float thac0cap = ((attacker->GetLevel() * 9) + 20);
if(thac0 > thac0cap)
{
thac0 = thac0cap;
}
d -= 10.0 * (a_diff / thac0);
}
else if(mit_roll > atk_roll)
{
float m_diff = (mit_roll - atk_roll);
float thac20 = mitigation_rating * RuleR(Combat, ACthac20Factor);
float thac20cap = ((defender->GetLevel() * 9) + 20);
if(thac20 > thac20cap)
{
thac20 = thac20cap;
}
d += 10 * (m_diff / thac20);
}
if(d < 0.0)
{
d = 0.0;
}
if(d > 20)
{
d = 20.0;
}
float interval = (damage - minhit) / 20.0;
damage = damage - ((int)d * interval);
}
else{
damage = GetMeleeMitDmg(attacker, damage, minhit, mitigation_rating, attack_rating);
} else {
////////////////////////////////////////////////////////
// Scorpious2k: Include AC in the calculation
// use serverop variables to set values
@ -755,17 +700,100 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac
if(damage != 0 && damage < minhit)
damage = minhit;
//reduce the damage from shielding item and aa based on the min dmg
//spells offer pure mitigation
damage -= (minhit * defender->itembonuses.MeleeMitigation / 100);
damage -= (damage * defender->spellbonuses.MeleeMitigation / 100);
}
//reduce the damage from shielding item and aa based on the min dmg
//spells offer pure mitigation
damage -= (minhit * defender->itembonuses.MeleeMitigation / 100);
damage -= (damage * defender->spellbonuses.MeleeMitigation / 100);
if(damage < 0)
if (damage < 0)
damage = 0;
}
// This is called when the Mob is the one being hit
int32 Mob::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit,
float mit_rating, float atk_rating)
{
float d = 10.0;
float mit_roll = MakeRandomFloat(0, mit_rating);
float atk_roll = MakeRandomFloat(0, atk_rating);
if (atk_roll > mit_roll) {
float a_diff = atk_roll - mit_roll;
float thac0 = atk_rating * RuleR(Combat, ACthac0Factor);
float thac0cap = attacker->GetLevel() * 9 + 20;
if (thac0 > thac0cap)
thac0 = thac0cap;
d -= 10.0 * (a_diff / thac0);
} else if (mit_roll > atk_roll) {
float m_diff = mit_roll - atk_roll;
float thac20 = mit_rating * RuleR(Combat, ACthac20Factor);
float thac20cap = GetLevel() * 9 + 20;
if (thac20 > thac20cap)
thac20 = thac20cap;
d += 10.0 * (m_diff / thac20);
}
if (d < 0.0)
d = 0.0;
else if (d > 20.0)
d = 20.0;
float interval = (damage - minhit) / 20.0;
damage -= ((int)d * interval);
damage -= (minhit * itembonuses.MeleeMitigation / 100);
damage -= (damage * spellbonuses.MeleeMitigation / 100);
return damage;
}
// This is called when the Client is the one being hit
int32 Client::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit,
float mit_rating, float atk_rating)
{
if (!attacker->IsNPC() || RuleB(Combat, UseOldDamageIntervalRules))
return Mob::GetMeleeMitDmg(attacker, damage, minhit, mit_rating, atk_rating);
int d = 10;
// floats for the rounding issues
float dmg_interval = (damage - minhit) / 19.0;
float dmg_bonus = minhit - dmg_interval;
float spellMeleeMit = spellbonuses.MeleeMitigation / 100.0;
if (GetClass() == WARRIOR)
spellMeleeMit += 0.05;
dmg_bonus -= dmg_bonus * (itembonuses.MeleeMitigation / 100.0);
dmg_interval -= dmg_interval * spellMeleeMit;
float mit_roll = MakeRandomFloat(0, mit_rating);
float atk_roll = MakeRandomFloat(0, atk_rating);
if (atk_roll > mit_roll) {
float a_diff = atk_roll - mit_roll;
float thac0 = atk_rating * RuleR(Combat, ACthac0Factor);
float thac0cap = attacker->GetLevel() * 9 + 20;
if (thac0 > thac0cap)
thac0 = thac0cap;
d += 10 * (a_diff / thac0);
} else if (mit_roll > atk_roll) {
float m_diff = mit_roll - atk_roll;
float thac20 = mit_rating * RuleR(Combat, ACthac20Factor);
float thac20cap = GetLevel() * 9 + 20;
if (thac20 > thac20cap)
thac20 = thac20cap;
d -= 10 * (m_diff / thac20);
}
if (d < 1)
d = 1;
else if (d > 20)
d = 20;
return static_cast<int32>((dmg_bonus + dmg_interval * d));
}
//Returns the weapon damage against the input mob
//if we cannot hit the mob with the current weapon we will get a value less than or equal to zero
//Else we know we can hit.
@ -1251,7 +1279,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
hate *= opts->hate_percent;
hate += opts->hate_flat;
}
//check to see if we hit..
if(!other->CheckHitChance(this, skillinuse, Hand)) {
mlog(COMBAT__ATTACKS, "Attack missed. Damage set to 0.");
@ -1308,6 +1336,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
// 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);
@ -1318,19 +1347,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
if (IsDead()) return false;
if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap))
{
int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap;
if(lifetap_amt > 100)
lifetap_amt = 100;
MeleeLifeTap(damage);
lifetap_amt = damage * lifetap_amt / 100;
mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage);
//heal self for damage done..
HealDamage(lifetap_amt);
}
if (damage > 0)
CheckNumHitsRemaining(5);
//break invis when you attack
if(invisible) {
@ -1882,6 +1902,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
mlog(COMBAT__HITS, "Generating hate %d towards %s", hate, GetName());
// now add done damage to the hate list
other->AddToHateList(this, hate);
} else {
if(opts) {
damage *= opts->damage_percent;
@ -1938,6 +1959,11 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
if (HasDied()) //killed by damage shield ect
return false;
MeleeLifeTap(damage);
if (damage > 0)
CheckNumHitsRemaining(5);
//break invis when you attack
if(invisible) {
mlog(COMBAT__ATTACKS, "Removing invisibility due to melee attack.");
@ -2411,7 +2437,9 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
}
void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
assert(other != nullptr);
if (other == this)
return;
@ -2492,6 +2520,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
if(damage > GetHP())
damage = GetHP();
if (spellbonuses.ImprovedTaunt[1] && (GetLevel() < spellbonuses.ImprovedTaunt[0])
&& other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID()))
hate = (hate*spellbonuses.ImprovedTaunt[1])/100;
hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic);
if(other->IsClient())
@ -3241,8 +3273,28 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
}
// If this is a DoT, use DoT Shielding...
if(iBuffTic)
damage -= (damage * itembonuses.DoTShielding / 100);
if(iBuffTic) {
damage -= (damage * itembonuses.DoTShielding / 100);
if (spellbonuses.MitigateDotRune[0]){
slot = spellbonuses.MitigateDotRune[1];
if(slot >= 0)
{
int damage_to_reduce = damage * spellbonuses.MitigateDotRune[0] / 100;
if(damage_to_reduce > buffs[slot].dot_rune)
{
damage -= damage_to_reduce;
if(!TryFadeEffect(slot))
BuffFadeBySlot(slot);
}
else
{
buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce);
damage -= damage_to_reduce;
}
}
}
}
// This must be a DD then so lets apply Spell Shielding and runes.
else
@ -3310,7 +3362,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
BuffFadeBySlot(slot);
}
else{
buffs[slot].melee_rune = (buffs[slot].magic_rune - damage);
buffs[slot].magic_rune = (buffs[slot].magic_rune - damage);
}
}
}
@ -3434,7 +3486,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
mlog(COMBAT__DAMAGE, "Avoiding %d damage due to invulnerability.", damage);
damage = -5;
}
if( spell_id != SPELL_UNKNOWN || attacker == nullptr )
avoidable = false;
@ -3444,6 +3496,13 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
DamageShield(attacker);
}
if (spell_id == SPELL_UNKNOWN && skill_used) {
CheckNumHitsRemaining(1); //Incoming Hit Attempts
if (attacker)
attacker->CheckNumHitsRemaining(2); //Outgoing Hit Attempts
}
if(attacker){
if(attacker->IsClient()){
if(!RuleB(Combat, EXPFromDmgShield)) {
@ -3514,16 +3573,20 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
}
ReduceAllDamage(damage);
if (skill_used)
CheckNumHitsRemaining(6); //Incomming Hit Success on Defender
if(IsClient() && CastToClient()->sneaking){
CastToClient()->sneaking = false;
SendAppearancePacket(AT_Sneak, 0);
}
if(attacker && attacker->IsClient() && attacker->CastToClient()->sneaking){
attacker->CastToClient()->sneaking = false;
attacker->SendAppearancePacket(AT_Sneak, 0);
}
ReduceAllDamage(damage);
if(IsClient() && CastToClient()->sneaking){
CastToClient()->sneaking = false;
SendAppearancePacket(AT_Sneak, 0);
}
if(attacker && attacker->IsClient() && attacker->CastToClient()->sneaking){
attacker->CastToClient()->sneaking = false;
attacker->SendAppearancePacket(AT_Sneak, 0);
}
//final damage has been determined.
SetHP(GetHP() - damage);
@ -3770,6 +3833,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
}
}
} //end packet sending
}

View File

@ -1216,6 +1216,18 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
case SE_HealRate:
newbon->HealRate += base1;
break;
case SE_MeleeLifetap:
{
if((base1 < 0) && (newbon->MeleeLifetap > base1))
newbon->MeleeLifetap = base1;
else if(newbon->MeleeLifetap < base1)
newbon->MeleeLifetap = base1;
break;
}
}
}
}
@ -1230,8 +1242,12 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
uint32 buff_count = GetMaxTotalSlots();
for(i = 0; i < buff_count; i++) {
if(buffs[i].spellid != SPELL_UNKNOWN)
if(buffs[i].spellid != SPELL_UNKNOWN){
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, buffs[i].ticsremaining,i);
if (buffs[i].numhits > 0)
Numhits(true);
}
}
//Removes the spell bonuses that are effected by a 'negate' debuff.
@ -1591,12 +1607,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
newbon->reflect_chance += effect_value;
break;
case SE_SingingSkill:
{
if(effect_value > newbon->singingMod)
newbon->singingMod = effect_value;
case SE_Amplification:
newbon->Amplification += effect_value;
break;
}
case SE_ChangeAggro:
newbon->hatemod += effect_value;
@ -1750,7 +1763,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
else if((effect_value < 0) && (newbon->MeleeLifetap > effect_value))
newbon->MeleeLifetap = spells[spell_id].base[i];
if(newbon->MeleeLifetap < spells[spell_id].base[i])
else if(newbon->MeleeLifetap < spells[spell_id].base[i])
newbon->MeleeLifetap = spells[spell_id].base[i];
break;
}
@ -2223,6 +2236,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
}
break;
}
case SE_MitigateDotDamage:
{
if (newbon->MitigateDotRune[0] < effect_value){
newbon->MitigateDotRune[0] = effect_value;
newbon->MitigateDotRune[1] = buffslot;
}
break;
}
case SE_ManaAbsorbPercentDamage:
{
@ -2480,7 +2502,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
break;
}
case SE_TriggerOnValueAmount:
case SE_TriggerOnReqTarget:
case SE_TriggerOnReqCaster:
newbon->TriggerOnValueAmount = true;
break;
@ -2488,6 +2511,19 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
newbon->DivineAura = true;
break;
case SE_ImprovedTaunt:
if (newbon->ImprovedTaunt[0] < effect_value) {
newbon->ImprovedTaunt[0] = effect_value;
newbon->ImprovedTaunt[1] = spells[spell_id].base2[i];
newbon->ImprovedTaunt[2] = buffslot;
}
break;
case SE_DistanceRemoval:
newbon->DistanceRemoval = true;
break;
}
}
}
@ -3099,10 +3135,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
itembonuses.reflect_chance = effect_value;
break;
case SE_SingingSkill:
spellbonuses.singingMod = effect_value;
itembonuses.singingMod = effect_value;
aabonuses.singingMod = effect_value;
case SE_Amplification:
spellbonuses.Amplification = effect_value;
itembonuses.Amplification = effect_value;
aabonuses.Amplification = effect_value;
break;
case SE_ChangeAggro:
@ -3533,6 +3569,11 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
spellbonuses.MitigateSpellRune[1] = -1;
break;
case SE_MitigateDotDamage:
spellbonuses.MitigateDotRune[0] = effect_value;
spellbonuses.MitigateDotRune[1] = -1;
break;
case SE_ManaAbsorbPercentDamage:
spellbonuses.ManaAbsorbPercentDamage[0] = effect_value;
spellbonuses.ManaAbsorbPercentDamage[1] = -1;
@ -3816,7 +3857,16 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
itembonuses.CriticalMend = effect_value;
aabonuses.CriticalMend = effect_value;
break;
case SE_DistanceRemoval:
spellbonuses.DistanceRemoval = effect_value;
break;
case SE_ImprovedTaunt:
spellbonuses.ImprovedTaunt[0] = effect_value;
spellbonuses.ImprovedTaunt[1] = effect_value;
spellbonuses.ImprovedTaunt[2] = -1;
}
}
}

View File

@ -2476,7 +2476,7 @@ void Bot::SaveBuffs() {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO botbuffs (BotId, SpellId, CasterLevel, DurationFormula, "
"TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, "
"DeathSaveSuccessChance, CasterAARank, Persistent) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);",
"dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);",
GetBotID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula,
buffs[BuffCount].ticsremaining,
CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
@ -2484,8 +2484,12 @@ void Bot::SaveBuffs() {
CalculateCurseCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune,
buffs[BuffCount].deathSaveSuccessChance,
buffs[BuffCount].deathsaveCasterAARank, IsPersistent), TempErrorMessageBuffer)) {
buffs[BuffCount].dot_rune,
buffs[BuffCount].caston_x,
IsPersistent,
buffs[BuffCount].caston_y,
buffs[BuffCount].caston_z,
buffs[BuffCount].ExtraDIChance), TempErrorMessageBuffer)) {
errorMessage = std::string(TempErrorMessageBuffer);
safe_delete(Query);
Query = 0;
@ -2515,7 +2519,7 @@ void Bot::LoadBuffs() {
bool BuffsLoaded = false;
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) {
errorMessage = std::string(TempErrorMessageBuffer);
}
else {
@ -2541,8 +2545,8 @@ void Bot::LoadBuffs() {
buffs[BuffCount].numhits = atoi(DataRow[8]);
buffs[BuffCount].melee_rune = atoi(DataRow[9]);
buffs[BuffCount].magic_rune = atoi(DataRow[10]);
buffs[BuffCount].deathSaveSuccessChance = atoi(DataRow[11]);
buffs[BuffCount].deathsaveCasterAARank = atoi(DataRow[12]);
buffs[BuffCount].dot_rune = atoi(DataRow[11]);
buffs[BuffCount].caston_x = atoi(DataRow[12]);
buffs[BuffCount].casterid = 0;
bool IsPersistent = false;
@ -2550,6 +2554,10 @@ void Bot::LoadBuffs() {
if(atoi(DataRow[13]))
IsPersistent = true;
buffs[BuffCount].caston_y = atoi(DataRow[14]);
buffs[BuffCount].caston_z = atoi(DataRow[15]);
buffs[BuffCount].ExtraDIChance = atoi(DataRow[16]);
buffs[BuffCount].persistant_buff = IsPersistent;
BuffCount++;
@ -3377,6 +3385,9 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
if (HasDied())
return;
if (damage > 0)
CheckNumHitsRemaining(5);
if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && MakeRandomInt(0, 99) < 25){
SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff);
other->Stun(100);
@ -6593,18 +6604,10 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
if (GetHP() < 0) return false;
if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap))
{
int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap;
if(lifetap_amt > 100)
lifetap_amt = 100;
MeleeLifeTap(damage);
lifetap_amt = damage * lifetap_amt / 100;
mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage);
//heal self for damage done..
HealDamage(lifetap_amt);
}
if (damage > 0)
CheckNumHitsRemaining(5);
//break invis when you attack
if(invisible) {
@ -6823,13 +6826,6 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id)
SpellSkill_Found = true;
break;
case SE_LimitSpellSubclass:{
int16 spell_skill = spell.skill * -1;
if(base1 == spell_skill)
LimitFound = true;
break;
}
case SE_LimitClass:
//Do not use this limit more then once per spell. If multiple class, treat value like items would.
if (!PassLimitClass(base1, GetClass()))
@ -7428,13 +7424,6 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
SpellSkill_Found = true;
break;
case SE_LimitSpellSubclass:{
int16 spell_skill = spell.skill * -1;
if(focus_spell.base[i] == spell_skill)
return 0;
break;
}
case SE_LimitClass:
//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()))
@ -8083,6 +8072,9 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if(!GetTarget())return;
if (HasDied()) return;
if (max_damage > 0)
CheckNumHitsRemaining(5);
//[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){
int kb_chance = 25;
@ -12975,7 +12967,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
pacer->Say("Trying to pacify %s \n", target->GetCleanName());
if(pacer->Bot_Command_CalmTarget(target)) {
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate))
//if(pacer->IsPacified(target))
c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
return;
@ -12991,7 +12983,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
pacer->Say("Trying to pacify %s \n", target->GetCleanName());
if(pacer->Bot_Command_CalmTarget(target)) {
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate))
//if(pacer->IsPacified(target))
c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
return;
@ -16315,7 +16307,7 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) {
std::string WindowText;
int LastCon = -1;
int CurrentCon = 0;
Mob* curMob = NULL;
Mob* curMob = nullptr;
uint32 array_counter = 0;

View File

@ -6045,11 +6045,10 @@ void Client::NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra)
}
}
bool Client::IsDraggingCorpse(const char *CorpseName)
bool Client::IsDraggingCorpse(uint16 CorpseID)
{
for(std::list<std::string>::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
{
if(!strcasecmp((*Iterator).c_str(), CorpseName))
for (auto It = DraggedCorpses.begin(); It != DraggedCorpses.end(); ++It) {
if (It->second == CorpseID)
return true;
}
@ -6058,20 +6057,22 @@ bool Client::IsDraggingCorpse(const char *CorpseName)
void Client::DragCorpses()
{
for(std::list<std::string>::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
{
Mob* corpse = entity_list.GetMob((*Iterator).c_str());
for (auto It = DraggedCorpses.begin(); It != DraggedCorpses.end(); ++It) {
Mob *corpse = entity_list.GetMob(It->second);
if(corpse && corpse->IsPlayerCorpse() && (DistNoRootNoZ(*corpse) <= RuleR(Character, DragCorpseDistance)))
if (corpse && corpse->IsPlayerCorpse() &&
(DistNoRootNoZ(*corpse) <= RuleR(Character, DragCorpseDistance)))
continue;
if(!corpse || !corpse->IsPlayerCorpse() || corpse->CastToCorpse()->IsBeingLooted() || !corpse->CastToCorpse()->Summon(this, false, false))
{
if (!corpse || !corpse->IsPlayerCorpse() ||
corpse->CastToCorpse()->IsBeingLooted() ||
!corpse->CastToCorpse()->Summon(this, false, false)) {
Message_StringID(MT_DefaultText, CORPSEDRAG_STOP);
Iterator = DraggedCorpses.erase(Iterator);
It = DraggedCorpses.erase(It);
}
}
}
void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_override, int pet_count, int pet_duration)
{
if(!target || !IsValidSpell(spell_id) || this->GetID() == target->GetID())

View File

@ -221,6 +221,7 @@ public:
virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); }
virtual Group* GetGroup() { return entity_list.GetGroupByClient(this); }
virtual inline bool IsBerserk() { return berserk; }
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
void AI_Init();
void AI_Start(uint32 iMoveDelay = 0);
@ -1077,7 +1078,7 @@ public:
void ClearHover();
inline bool IsBlockedBuff(int16 SpellID) { return PlayerBlockedBuffs.find(SpellID) != PlayerBlockedBuffs.end(); }
inline bool IsBlockedPetBuff(int16 SpellID) { return PetBlockedBuffs.find(SpellID) != PetBlockedBuffs.end(); }
bool IsDraggingCorpse(const char* CorpseName);
bool IsDraggingCorpse(uint16 CorpseID);
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
void DragCorpses();
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
@ -1480,7 +1481,7 @@ private:
std::set<uint32> PlayerBlockedBuffs;
std::set<uint32> PetBlockedBuffs;
std::list<std::string> DraggedCorpses;
std::list<std::pair<std::string, uint16> > DraggedCorpses;
uint8 MaxXTargets;
bool XTargetAutoAddHaters;

View File

@ -1857,7 +1857,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const
effectmod = itembonuses.singingMod;
else
effectmod = spellbonuses.singingMod;
effectmod += aabonuses.singingMod;
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
break;
default:
effectmod = 10;

View File

@ -9466,7 +9466,7 @@ void Client::CompleteConnect()
case SE_AddMeleeProc:
case SE_WeaponProc:
{
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100+spells[buffs[j1].spellid].base2[x1]);
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100+spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
break;
}
case SE_DefensiveProc:
@ -12379,7 +12379,7 @@ void Client::Handle_OP_CorpseDrag(const EQApplicationPacket *app)
if(!corpse || !corpse->IsPlayerCorpse() || corpse->CastToCorpse()->IsBeingLooted())
return;
Client *c = entity_list.FindCorpseDragger(cds->CorpseName);
Client *c = entity_list.FindCorpseDragger(corpse->GetID());
if(c)
{
@ -12394,7 +12394,7 @@ void Client::Handle_OP_CorpseDrag(const EQApplicationPacket *app)
if(!corpse->CastToCorpse()->Summon(this, false, true))
return;
DraggedCorpses.push_back(cds->CorpseName);
DraggedCorpses.push_back(std::pair<std::string, uint16>(cds->CorpseName, corpse->GetID()));
Message_StringID(MT_DefaultText, CORPSEDRAG_BEGIN, cds->CorpseName);
}
@ -12408,9 +12408,9 @@ void Client::Handle_OP_CorpseDrop(const EQApplicationPacket *app)
return;
}
for(std::list<std::string>::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
for (auto Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
{
if(!strcasecmp((*Iterator).c_str(), (const char *)app->pBuffer))
if(!strcasecmp(Iterator->first.c_str(), (const char *)app->pBuffer))
{
Message_StringID(MT_DefaultText, CORPSEDRAG_STOP);
Iterator = DraggedCorpses.erase(Iterator);

View File

@ -11047,9 +11047,6 @@ void command_showbonusstats(Client *c, const Seperator *sep)
c->Message(0, " Target Spell Bonuses:");
c->Message(0, " Accuracy: %i%% Divine Save: %i%%",c->GetTarget()->GetSpellBonuses().Accuracy, c->GetTarget()->GetSpellBonuses().DivineSaveChance);
c->Message(0, " Flurry: %i%% HitChance: %i%% ",c->GetTarget()->GetSpellBonuses().FlurryChance, c->GetTarget()->GetSpellBonuses().HitChance / 15);
int deathsaveslot = c->GetTarget()->GetBuffSlotFromType(SE_DeathSave);
int dschance = deathsaveslot >= 0 ? c->GetTarget()->GetBuffs()[deathsaveslot].deathSaveSuccessChance : 0;
c->Message(0, " Death Save: %i%%",dschance);
}
c->Message(0, " Effective Casting Level: %i",c->GetTarget()->GetCasterLevel(0));
}

View File

@ -155,8 +155,11 @@ struct Buffs_Struct {
uint32 numhits; //the number of physical hits this buff can take before it fades away, lots of druid armor spells take advantage of this mixed with powerful effects
uint32 melee_rune;
uint32 magic_rune;
uint8 deathSaveSuccessChance;
uint8 deathsaveCasterAARank;
uint32 dot_rune;
int32 caston_x;
int32 caston_y;
int32 caston_z;
int32 ExtraDIChance;
bool persistant_buff;
bool client; //True if the caster is a client
bool UpdateClient;
@ -231,6 +234,7 @@ struct StatBonuses {
int effective_casting_level;
int reflect_chance; // chance to reflect incoming spell
uint16 singingMod;
uint16 Amplification; // stacks with singingMod
uint16 brassMod;
uint16 percussionMod;
uint16 windMod;
@ -319,6 +323,7 @@ struct StatBonuses {
uint16 MeleeThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger.
uint16 SpellThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger.
uint16 MitigateSpellRune[2]; // 0 = Mitigation value 1 = Buff Slot
uint16 MitigateDotRune[2]; // 0 = Mitigation value 1 = Buff Slot
uint32 TriggerMeleeThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger
uint32 TriggerSpellThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger
uint16 ManaAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Buff Slot
@ -328,6 +333,8 @@ struct StatBonuses {
bool CriticalHealDecay; // increase critical heal chance, decays based on spell level cast
bool CriticalDotDecay; // increase critical dot chance, decays based on spell level cast
bool DivineAura; // invulnerability
bool DistanceRemoval; // Check if Cancle if Moved effect is present
int16 ImprovedTaunt[3]; // 0 = Max Level 1 = Aggro modifier 2 = buffid
//bool AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect
//bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect

View File

@ -4512,11 +4512,11 @@ void EntityList::GetTargetsForConeArea(Mob *start, uint32 radius, uint32 height,
}
}
Client *EntityList::FindCorpseDragger(const char *CorpseName)
Client *EntityList::FindCorpseDragger(uint16 CorpseID)
{
auto it = client_list.begin();
while (it != client_list.end()) {
if (it->second->IsDraggingCorpse(CorpseName))
if (it->second->IsDraggingCorpse(CorpseID))
return it->second;
++it;
}

View File

@ -167,7 +167,7 @@ public:
Spawn2* GetSpawnByID(uint32 id);
Client* FindCorpseDragger(const char *CorpseName);
Client* FindCorpseDragger(uint16 CorpseID);
inline Object *GetObjectByID(uint16 id)
{ return object_list.count(id) ? object_list.at(id) : nullptr; }

View File

@ -268,6 +268,9 @@ Mob *HateList::GetTop(Mob *center)
Mob* top = nullptr;
int32 hate = -1;
if(center == nullptr)
return nullptr;
if (RuleB(Aggro,SmartAggroList)){
Mob* topClientTypeInRange = nullptr;
int32 hateClientTypeInRange = -1;
@ -380,15 +383,15 @@ Mob *HateList::GetTop(Mob *center)
}
if(!isTopClientType)
return topClientTypeInRange;
return topClientTypeInRange ? topClientTypeInRange : nullptr;
return top;
return top ? top : nullptr;
}
else {
if(top == nullptr && skipped_count > 0) {
return center->GetTarget();
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top;
return top ? top : nullptr;
}
}
else{
@ -413,10 +416,11 @@ Mob *HateList::GetTop(Mob *center)
++iterator;
}
if(top == nullptr && skipped_count > 0) {
return center->GetTarget();
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top;
return top ? top : nullptr;
}
return nullptr;
}
Mob *HateList::GetMostHate(){

View File

@ -908,6 +908,16 @@ void Lua_Mob::SetHate(Lua_Mob other, int hate, int damage) {
self->SetHate(other, hate, damage);
}
void Lua_Mob::HalveAggro(Lua_Mob other) {
Lua_Safe_Call_Void();
self->HalveAggro(other);
}
void Lua_Mob::DoubleAggro(Lua_Mob other) {
Lua_Safe_Call_Void();
self->DoubleAggro(other);
}
uint32 Lua_Mob::GetHateAmount(Lua_Mob target) {
Lua_Safe_Call_Int();
return self->GetHateAmount(target);
@ -1967,6 +1977,8 @@ luabind::scope lua_register_mob() {
.def("SetHate", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::SetHate)
.def("SetHate", (void(Lua_Mob::*)(Lua_Mob,int))&Lua_Mob::SetHate)
.def("SetHate", (void(Lua_Mob::*)(Lua_Mob,int,int))&Lua_Mob::SetHate)
.def("HalveAggro", &Lua_Mob::HalveAggro)
.def("DoubleAggro", &Lua_Mob::DoubleAggro)
.def("GetHateAmount", (uint32(Lua_Mob::*)(Lua_Mob))&Lua_Mob::GetHateAmount)
.def("GetHateAmount", (uint32(Lua_Mob::*)(Lua_Mob,bool))&Lua_Mob::GetHateAmount)
.def("GetDamageAmount", (uint32(Lua_Mob::*)(Lua_Mob))&Lua_Mob::GetDamageAmount)

View File

@ -192,6 +192,8 @@ public:
void SetHate(Lua_Mob other);
void SetHate(Lua_Mob other, int hate);
void SetHate(Lua_Mob other, int hate, int damage);
void HalveAggro(Lua_Mob other);
void DoubleAggro(Lua_Mob other);
uint32 GetHateAmount(Lua_Mob target);
uint32 GetHateAmount(Lua_Mob target, bool is_damage);
uint32 GetDamageAmount(Lua_Mob target);
@ -346,4 +348,4 @@ public:
};
#endif
#endif
#endif

View File

@ -3670,7 +3670,7 @@ MercSpell Merc::GetBestMercSpellForHate(Merc* caster) {
result.time_cancast = 0;
if(caster) {
std::list<MercSpell> mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Calm);
std::list<MercSpell> mercSpellList = GetMercSpellsForSpellEffect(caster, SE_InstantHate);
for(std::list<MercSpell>::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order

View File

@ -3228,11 +3228,20 @@ void Mob::TryApplyEffect(Mob *target, uint32 spell_id)
void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsPet)
{
/*
At present time there is no obvious difference between ReqTarget and ReqCaster
ReqTarget is typically used in spells cast on a target where the trigger occurs on that target.
ReqCaster is typically self only spells where the triggers on self.
Regardless both trigger on the owner of the buff.
*/
/*
Base2 Range: 1004 = Below < 80% HP
Base2 Range: 500-520 = Below (base2 - 500)*5 HP
Base2 Range: 521 = Below (?) Mana UKNOWN - Will assume its 20% unless proven otherwise
Base2 Range: 522 = Below (40%) Endurance
Base2 Range: 523 = Below (40%) Mana
Base2 Range: 220-? = Number of pets on hatelist to trigger (base2 - 220) (Set at 30 pets max for now)
38311 = < 10% mana;
*/
if (!spellbonuses.TriggerOnValueAmount)
@ -3250,21 +3259,25 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
for(int i = 0; i < EFFECT_COUNT; i++){
if (spells[spell_id].effectid[i] == SE_TriggerOnValueAmount){
if ((spells[spell_id].effectid[i] == SE_TriggerOnReqTarget) || (spells[spell_id].effectid[i] == SE_TriggerOnReqCaster)) {
int base2 = spells[spell_id].base2[i];
bool use_spell = false;
if (IsHP){
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5){
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5)
use_spell = true;
else if (base2 = 1004 && GetHPRatio() < 80)
use_spell = true;
}
}
else if (IsMana){
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40)) {
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40))
use_spell = true;
else if (base2 = 38311 && GetManaRatio() < 10)
use_spell = true;
}
}
else if (IsEndur){
@ -3283,10 +3296,6 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
if (use_spell){
SpellFinished(spells[spell_id].base[i], this, 10, 0, -1, spells[spell_id].ResistDiff);
/*Note, spell data shows numhits values of 0 or 1, however many descriptions of these spells indicate they should
be fading when consumed even with numhits of 0 (It makes sense they should fade...).
Unless proven otherwise, they should fade when triggered. */
if(!TryFadeEffect(e))
BuffFadeBySlot(e);
}
@ -3412,8 +3421,6 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
if(skilldmg_mod < -100)
skilldmg_mod = -100;
CheckNumHitsRemaining(6);
return skilldmg_mod;
}
@ -4315,17 +4322,38 @@ int16 Mob::GetSkillDmgAmt(uint16 skill)
skill_dmg += spellbonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount2[HIGHEST_SKILL+1]
+ itembonuses.SkillDamageAmount2[skill] + spellbonuses.SkillDamageAmount2[skill];
CheckNumHitsRemaining(5);
return skill_dmg;
}
void Mob::MeleeLifeTap(int32 damage) {
if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap || aabonuses.MeleeLifetap ))
{
int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap;
if(lifetap_amt > 100)
lifetap_amt = 100;
else if (lifetap_amt < -99)
lifetap_amt = -99;
lifetap_amt = damage * lifetap_amt / 100;
mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage);
//heal self for damage done..
HealDamage(lifetap_amt);
}
}
bool Mob::TryReflectSpell(uint32 spell_id)
{
if(!GetTarget())
return false;
if (!spells[spell_id].reflectable)
return false;
if(MakeRandomInt(0, 99) < (GetTarget()->itembonuses.reflect_chance + GetTarget()->spellbonuses.reflect_chance))
int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance;
if(chance && MakeRandomInt(0, 99) < chance)
return true;
return false;

View File

@ -143,6 +143,7 @@ public:
virtual void DoRiposte(Mob* defender);
void ApplyMeleeDamageBonus(uint16 skill, int32 &damage);
virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr);
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
bool CombatRange(Mob* other);
virtual inline bool IsBerserk() { return false; } // only clients
@ -427,6 +428,8 @@ public:
bool bFrenzy = false, bool iBuffTic = false);
bool RemoveFromHateList(Mob* mob);
void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.Set(other,hate,damage);}
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate > 1 ? in_hate / 2 : 1)); }
void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate ? in_hate * 2 : 1)); }
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHate(tmob,is_dam);}
uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHate(tmob, true);}
Mob* GetHateTop() { return hate_list.GetTop(this);}
@ -497,7 +500,7 @@ public:
bool AddSkillProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
bool RemoveSkillProc(uint16 spell_id, bool bAll = false);
bool HasSkillProcs() const;
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3);
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false);
bool HasProcs() const;
@ -587,6 +590,9 @@ public:
int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false);
int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect);
int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg);
void MeleeLifeTap(int32 damage);
bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true);
bool ImprovedTaunt();
void ModSkillDmgTaken(SkillUseTypes skill_num, int value);
int16 GetModSkillDmgTaken(const SkillUseTypes skill_num);
@ -878,7 +884,7 @@ protected:
bool IsFullHP;
bool moved;
std::vector<std::string> RampageArray;
std::vector<uint16> RampageArray;
std::map<std::string, std::string> m_EntityVariables;
int16 SkillDmgTaken_Mod[HIGHEST_SKILL+2];

View File

@ -183,8 +183,7 @@ int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint1
//Sum of various resists rolled against a value of 200.
int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) {
int final = resist_chance + level_mod + resist_modifier + target_resist;
return(final);
return(resist_chance);
}
//Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event

View File

@ -476,6 +476,8 @@ int main(int argc, char** argv) {
entity_list.Clear();
parse->ClearInterfaces();
#ifdef EMBPERL
safe_delete(perl_parser);
#endif
@ -496,7 +498,7 @@ int main(int argc, char** argv) {
dbasync->StopThread();
safe_delete(taskmanager);
command_deinit();
safe_delete(parse);
CheckEQEMuErrorAndPause();
_log(ZONE__INIT, "Proper zone shutdown complete.");
return 0;

View File

@ -5341,6 +5341,72 @@ XS(XS_Mob_SetHate)
XSRETURN_EMPTY;
}
XS(XS_Mob_HalveAggro);
XS(XS_Mob_HalveAggro)
{
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::HalveAggro(THIS, other)");
{
Mob * THIS;
Mob * other;
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.");
if (sv_derived_from(ST(1), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(1)));
other = INT2PTR(Mob *,tmp);
}
else
Perl_croak(aTHX_ "other is not of type Mob");
if(other == nullptr)
Perl_croak(aTHX_ "other is nullptr, avoiding crash.");
THIS->HalveAggro(other);
}
XSRETURN_EMPTY;
}
XS(XS_Mob_DoubleAggro);
XS(XS_Mob_DoubleAggro)
{
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Mob::DoubleAggro(THIS, other)");
{
Mob * THIS;
Mob * other;
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.");
if (sv_derived_from(ST(1), "Mob")) {
IV tmp = SvIV((SV*)SvRV(ST(1)));
other = INT2PTR(Mob *,tmp);
}
else
Perl_croak(aTHX_ "other is not of type Mob");
if(other == nullptr)
Perl_croak(aTHX_ "other is nullptr, avoiding crash.");
THIS->DoubleAggro(other);
}
XSRETURN_EMPTY;
}
XS(XS_Mob_GetHateAmount); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_GetHateAmount)
{
@ -8274,6 +8340,8 @@ XS(boot_Mob)
newXSproto(strcpy(buf, "IsRooted"), XS_Mob_IsRooted, file, "$");
newXSproto(strcpy(buf, "AddToHateList"), XS_Mob_AddToHateList, file, "$$;$$$$$");
newXSproto(strcpy(buf, "SetHate"), XS_Mob_SetHate, file, "$$;$$");
newXSproto(strcpy(buf, "HalveAggro"), XS_Mob_HalveAggro, file, "$$");
newXSproto(strcpy(buf, "DoubleAggro"), XS_Mob_DoubleAggro, file, "$$");
newXSproto(strcpy(buf, "GetHateAmount"), XS_Mob_GetHateAmount, file, "$$;$");
newXSproto(strcpy(buf, "GetDamageAmount"), XS_Mob_GetDamageAmount, file, "$$");
newXSproto(strcpy(buf, "GetHateTop"), XS_Mob_GetHateTop, file, "$");

View File

@ -605,9 +605,9 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
// We need to reapply buff based procs
// We need to do this here so suspended pets also regain their procs.
if (spells[buffs[j1].spellid].base2[x1] == 0) {
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100);
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100, buffs[j1].spellid);
} else {
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].base2[x1]);
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
}
break;
case SE_Charm:

View File

@ -155,6 +155,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if(!GetTarget())return;
if (HasDied()) return;
if (max_damage > 0)
CheckNumHitsRemaining(5);
//[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){
int kb_chance = 25;
@ -606,14 +609,16 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
if(IsClient()){
const ItemInst *wpn = nullptr;
wpn = CastToClient()->GetInv().GetItem(SLOT_PRIMARY);
primaryweapondamage = GetWeaponDamage(other, wpn);
backstab_dmg = wpn->GetItem()->BackstabDmg;
for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i)
{
ItemInst *aug = wpn->GetAugment(i);
if(aug)
if(wpn) {
primaryweapondamage = GetWeaponDamage(other, wpn);
backstab_dmg = wpn->GetItem()->BackstabDmg;
for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i)
{
backstab_dmg += aug->GetItem()->BackstabDmg;
ItemInst *aug = wpn->GetAugment(i);
if(aug)
{
backstab_dmg += aug->GetItem()->BackstabDmg;
}
}
}
}
@ -948,6 +953,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
TryCriticalHit(other, SkillArchery, TotalDmg);
other->AddToHateList(this, hate, 0, false);
CheckNumHitsRemaining(5);
}
}
else
@ -1052,6 +1058,7 @@ void NPC::RangedAttack(Mob* other)
TryCriticalHit(GetTarget(), SkillArchery, TotalDmg);
GetTarget()->AddToHateList(this, hate, 0, false);
GetTarget()->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery);
CheckNumHitsRemaining(5);
}
else
{
@ -1270,6 +1277,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
TryCriticalHit(other, SkillThrowing, TotalDmg);
int32 hate = (2*WDmg);
other->AddToHateList(this, hate, 0, false);
CheckNumHitsRemaining(5);
}
}
@ -2181,6 +2189,8 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
if (HasDied())
return;
CheckNumHitsRemaining(5);
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skillinuse){
int kb_chance = 25;
kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100;

View File

@ -183,7 +183,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
numhit += caster->CastToClient()->GetFocusEffect(focusIncreaseNumHits, spell_id);
}
Numhits(true);
buffs[buffslot].numhits = numhit;
}
@ -218,83 +217,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
int32 dmg = effect_value;
if(dmg < 0)
{
/*Special Cases where Base2 is defined
Range 105 : Plant
Range 120 : Undead
Range 123 : Humanoid
Range 190 : No Raid boss flag *not implemented
Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented
Range 201 : Damage if HP > 75%
Range 221 - 299 : Causing damage dependent on how many pets/swarmpets are attacking your target.
Range 300 - 303 : UNKOWN *not implemented
Range 399 - 499 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect)
Range 500 - 599 : Heal if HP less than a specified value
Range 600 - 699 : Limit to Body Type [base2 - 600 = Body]
Range 818 - 819 : If Undead/If Not Undead
Range 835 - : Unknown *not implemented
Range 836 - 837 : Progression Server / Live Server *not implemented
Range 839 - : Unknown *not implemented
Range 10000+ : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement)
*/
if (spells[spell_id].base2[i] > 0){
//It is unlikely these effects would give a fail message (Need to confirm)
if (spells[spell_id].base2[i] == 105){
if (GetBodyType() != BT_Plant)
break;
}
else if (spells[spell_id].base2[i] == 120){
if (GetBodyType() != BT_Undead)
break;
}
else if (spells[spell_id].base2[i] == 123){
if (GetBodyType() != BT_Humanoid)
break;
}
//Limit to Body Type.
else if (spells[spell_id].base2[i] >= 600 && spells[spell_id].base2[i] <= 699){
if (GetBodyType() != (spells[spell_id].base2[i] - 600)){
//caster->Message_StringID(13,CANNOT_AFFECT_NPC);
break;
}
}
else if (spells[spell_id].base2[i] == 201){
if (GetHPRatio() < 75)
break;
}
//Limit to Race. *Not implemented on live
else if (spells[spell_id].base2[i] >= 10000 && spells[spell_id].base2[i] <= 11000){
if (GetRace() != (spells[spell_id].base2[i] - 10000)){
break;
}
}
//Limit to amount of pets
else if (spells[spell_id].base2[i] >= 221 && spells[spell_id].base2[i] <= 299){
bool allow_spell = false;
int count = hate_list.SummonedPetCount(this);
for (int base2_value = 221; base2_value <= 233; ++base2_value){
if (spells[spell_id].base2[i] == base2_value){
if (count >= (base2_value - 220)){
allow_spell = true;
break;
}
}
}
if (!allow_spell)
break;
}
}
if (!PassCastRestriction(false, spells[spell_id].base2[i], true))
break;
// take partial damage into account
dmg = (int32) (dmg * partial / 100);
@ -308,60 +232,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
}
else if(dmg > 0) {
//healing spell...
if (spells[spell_id].base2[i] > 0)
{
bool allow_spell = false;
//Heal only if HP within specified range. [Doesn't follow a set forumla for all values...]
if (spells[spell_id].base2[i] >= 400 && spells[spell_id].base2[i] <= 408){
for (int base2_value = 400; base2_value <= 408; ++base2_value){
if (spells[spell_id].base2[i] == base2_value){
if (spells[spell_id].base2[i] == 400){
if (GetHPRatio() <= 25){
allow_spell = true;
break;
}
}
else if (spells[spell_id].base2[i] == base2_value){
if (GetHPRatio() > 25+((base2_value - 401)*10) && GetHPRatio() <= 35+((base2_value - 401)*10)){
allow_spell = true;
break;
}
}
}
}
}
else if (spells[spell_id].base2[i] >= 500 && spells[spell_id].base2[i] <= 520){
for (int base2_value = 500; base2_value <= 520; ++base2_value){
if (spells[spell_id].base2[i] == base2_value){
if (spells[spell_id].base2[i] == base2_value){
if (GetHPRatio() < (base2_value - 500)*5) {
allow_spell = true;
break;
}
}
}
}
}
if (!PassCastRestriction(false, spells[spell_id].base2[i], false))
break;
else if (spells[spell_id].base2[i] == 399){
if (GetHPRatio() > 15 && GetHPRatio() <= 25){
allow_spell = true;
break;
}
}
if(!allow_spell)
break;
}
if(caster)
dmg = caster->GetActSpellHealing(spell_id, dmg, this);
@ -1410,6 +1284,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
break;
}
case SE_MitigateDotDamage:
{
buffs[buffslot].dot_rune = spells[spell_id].max[i];
break;
}
case SE_TriggerMeleeThreshold:
{
buffs[buffslot].melee_rune = spells[spell_id].base2[i];
@ -1422,7 +1302,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
break;
}
case SE_DistanceRemoval:
{
buffs[buffslot].caston_x = int(GetX());
buffs[buffslot].caston_y = int(GetY());
buffs[buffslot].caston_z = int(GetZ());
break;
}
case SE_Levitate:
{
#ifdef SPELL_EFFECT_SPAM
@ -1434,6 +1321,20 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
break;
}
case SE_DeathSave: {
int16 mod = 0;
if(caster) {
mod = caster->aabonuses.UnfailingDivinity +
caster->itembonuses.UnfailingDivinity +
caster->spellbonuses.UnfailingDivinity;
}
buffs[buffslot].ExtraDIChance = mod;
break;
}
case SE_Illusion:
{
#ifdef SPELL_EFFECT_SPAM
@ -1545,10 +1446,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
snprintf(effect_desc, _EDLEN, "Memory Blur: %d", effect_value);
#endif
int wipechance = spells[spell_id].base[i];
int bonus = spellbonuses.IncreaseChanceMemwipe + itembonuses.IncreaseChanceMemwipe + aabonuses.IncreaseChanceMemwipe;
int bonus = 0;
if (caster){
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
caster->itembonuses.IncreaseChanceMemwipe +
caster->aabonuses.IncreaseChanceMemwipe;
}
wipechance += wipechance*bonus/100;
if(MakeRandomInt(0, 100) < wipechance)
if(MakeRandomInt(0, 99) < wipechance)
{
if(IsAIControlled())
{
@ -1821,9 +1729,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
#endif
if(spells[spell_id].base2[i] == 0)
AddProcToWeapon(procid, false, 100);
AddProcToWeapon(procid, false, 100, spell_id);
else
AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100);
AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100, spell_id);
break;
}
@ -2487,30 +2395,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
break;
}
case SE_DeathSave: {
#ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Death Save: %+i", effect_value);
#endif
uint8 BonusChance = 0;
if(caster) {
BonusChance = caster->aabonuses.UnfailingDivinity +
caster->itembonuses.UnfailingDivinity +
caster->spellbonuses.UnfailingDivinity;
}
#ifdef SPELL_EFFECT_SPAM
//snprintf(effect_desc, _EDLEN, "Death Save Chance: %+i", SuccessChance);
#endif
//buffs[buffslot].deathSaveSuccessChance = SuccessChance;
//buffs[buffslot].deathsaveCasterAARank = caster->GetAA(aaUnfailingDivinity);
buffs[buffslot].deathsaveCasterAARank = BonusChance;
//SetDeathSaveChance(true);
break;
}
case SE_SummonAndResAllCorpses:
{
if(IsClient())
@ -2757,7 +2641,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_MeleeMitigation:
case SE_Reflect:
case SE_Screech:
case SE_SingingSkill:
case SE_Amplification:
case SE_MagicWeapon:
case SE_Hunger:
case SE_MagnifyVision:
@ -2793,7 +2677,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_ChangeAggro:
case SE_Hate2:
case SE_Identify:
case SE_Calm:
case SE_InstantHate:
case SE_ReduceHate:
case SE_SpellDamageShield:
case SE_ReverseDS:
@ -2889,7 +2773,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_MitigateDamageShield:
case SE_FcBaseEffects:
case SE_LimitClass:
case SE_LimitSpellSubclass:
case SE_BlockBehind:
case SE_ShieldBlock:
case SE_PetCriticalHit:
@ -2932,7 +2815,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_DoubleRangedAttack:
case SE_ShieldEquipHateMod:
case SE_ShieldEquipDmgMod:
case SE_TriggerOnValueAmount:
case SE_TriggerOnReqTarget:
case SE_LimitRace:
case SE_FcLimitUse:
case SE_FcMute:
@ -2942,6 +2825,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_IncreaseChanceMemwipe:
case SE_CriticalMend:
case SE_LimitCastTimeMax:
case SE_TriggerOnReqCaster:
{
break;
}
@ -3403,6 +3287,31 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
break;
}
case SE_WipeHateList:
{
int wipechance = spells[spell_id].base[i];
int bonus = 0;
if (caster){
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
caster->itembonuses.IncreaseChanceMemwipe +
caster->aabonuses.IncreaseChanceMemwipe;
}
wipechance += wipechance*bonus/100;
if(MakeRandomInt(0, 99) < wipechance)
{
if(IsAIControlled())
{
WipeHateList();
}
Message(13, "Your mind fogs. Who are my friends? Who are my enemies?... it was all so clear a moment ago...");
}
break;
}
case SE_Charm: {
if (!caster || !PassCharismaCheck(caster, this, spell_id)) {
BuffFadeByEffect(SE_Charm);
@ -3504,6 +3413,26 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
}
break;
}
case SE_DistanceRemoval:
{
if (spellbonuses.DistanceRemoval){
int distance = sqrt(
((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) +
((int(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) +
((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z))
);
if (distance > spells[spell_id].base[i]){
if(!TryFadeEffect(slot))
BuffFadeBySlot(slot , true);
}
break;
}
}
default:
{
// do we need to do anyting here?
@ -4152,13 +4081,12 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
}
break;
case SE_LimitCombatSkills:
if (base1 == 0){
if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs
LimitFailure = true;
}
break;
if (base1 == 0 && IsCombatSkill(spell_id)) //Exclude Discs
LimitFailure = true;
else if (base1 == 1 && !IsCombatSkill(spell_id)) //Exclude Spells
LimitFailure = true;
break;
case SE_LimitSpellGroup:
if(base1 < 0) {
@ -4555,10 +4483,10 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
break;
case SE_LimitCombatSkills:
if (focus_spell.base[i] == 0){
if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs
return 0;
}
if (focus_spell.base[i] == 0 && IsCombatSkill(spell_id)) //Exclude Disc
return 0;
else if (focus_spell.base[i] == 1 && !IsCombatSkill(spell_id)) //Include Spells
return 0;
break;
case SE_LimitSpellGroup:
@ -5376,11 +5304,13 @@ bool Mob::TryDeathSave() {
int SuccessChance = 0;
int buffSlot = spellbonuses.DeathSave[1];
uint8 UD_HealMod = buffs[buffSlot].deathsaveCasterAARank; //Contains value of UD heal modifier.
int16 UD_HealMod = 0;
uint32 HealAmt = 300; //Death Pact max Heal
if(buffSlot >= 0){
UD_HealMod = buffs[buffSlot].ExtraDIChance;
SuccessChance = ( (GetCHA() * (RuleI(Spells, DeathSaveCharismaMod))) + 1) / 10; //(CHA Mod Default = 3)
if (SuccessChance > 95)
@ -5445,6 +5375,8 @@ bool Mob::TryDeathSave() {
}
}
}
BuffFadeBySlot(buffSlot);
}
return false;
}
@ -5704,3 +5636,333 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){
return false;
}
bool Mob::ImprovedTaunt(){
if (spellbonuses.ImprovedTaunt[0]){
if (GetLevel() > spellbonuses.ImprovedTaunt[0])
return false;
if (spellbonuses.ImprovedTaunt[2] >= 0){
target = entity_list.GetMob(buffs[spellbonuses.ImprovedTaunt[2]].casterid);
if (target){
SetTarget(target);
return true;
}
else {
if(!TryFadeEffect(spellbonuses.ImprovedTaunt[2]))
BuffFadeBySlot(spellbonuses.ImprovedTaunt[2], true); //If caster killed removed effect.
}
}
}
return false;
}
bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDamage)
{
/*If return TRUE spell met all restrictions and can continue (this = target).
This check is used when the spell_new field CastRestriction is defined OR spell effect '0'(DD/Heal) has a defined limit
Range 1 : UNKNOWN
Range 100 : *Animal OR Humanoid
Range 101 : *Dragon
Range 102 : *Animal OR Insect
Range 103 : NOT USED
Range 104 : *Animal
Range 105 : Plant
Range 106 : *Giant
Range 107 : NOT USED
Range 108 : NOT Animal or Humaniod
Range 109 : *Bixie
Range 111 : *Harpy
Range 112 : *Sporali
Range 113 : *Kobold
Range 114 : *Shade Giant
Range 115 : *Drakkin
Range 116 : NOT USED
Range 117 : *Animal OR Plant
Range 118 : *Summoned
Range 119 : *Firepet
Range 120 : Undead
Range 121 : *Living (NOT Undead)
Range 122 : *Fairy
Range 123 : Humanoid
Range 124 : *Undead HP < 10%
Range 125 : *Clockwork HP < 10%
Range 126 : *Wisp HP < 10%
Range 127-130 : UNKNOWN
Range 150 : UNKNOWN
Range 190 : No Raid boss flag *not implemented
Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented
Range 201 : Damage if HP > 75%
Range 203 : Damage if HP < 20%
Range 216 : TARGET NOT IN COMBAT
Range 221 - 249 : Causing damage dependent on how many pets/swarmpets are attacking your target.
Range 250 : Damage if HP < 35%
Range 300 - 303 : UNKOWN *not implemented
Range 304 : Chain + Plate class (buffs)
Range 399 - 409 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect)
Range 410 - 411 : UNKOWN
Range 500 - 599 : Heal if HP less than a specified value
Range 600 - 699 : Limit to Body Type [base2 - 600 = Body]
Range 700 : UNKNOWN
Range 701 : NOT PET
Range 800 : UKNOWN
Range 818 - 819 : If Undead/If Not Undead
Range 820 - 822 : UKNOWN
Range 835 : Unknown *not implemented
Range 836 - 837 : Progression Server / Live Server *not implemented
Range 839 : Unknown *not implemented
Range 842 - 844 : Humaniod lv MAX ((842 - 800) * 2)
Range 845 - 847 : UNKNOWN
Range 10000 - 11000 : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement)
THIS IS A WORK IN PROGRESS
*/
if (value <= 0)
return true;
if (IsDamage || UseCastRestriction) {
switch(value)
{
case 100:
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Humanoid))
return true;
break;
case 101:
if (GetBodyType() == BT_Dragon || GetBodyType() == BT_VeliousDragon || GetBodyType() == BT_Dragon3)
return true;
break;
case 102:
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Insect))
return true;
break;
case 104:
if (GetBodyType() == BT_Animal)
return true;
break;
case 105:
if (GetBodyType() == BT_Plant)
return true;
break;
case 106:
if (GetBodyType() == BT_Giant)
return true;
break;
case 108:
if ((GetBodyType() != BT_Animal) || (GetBodyType() != BT_Humanoid))
return true;
break;
case 109:
if ((GetRace() == 520) ||(GetRace() == 79))
return true;
break;
case 111:
if ((GetRace() == 527) ||(GetRace() == 11))
return true;
break;
case 112:
if ((GetRace() == 456) ||(GetRace() == 28))
return true;
break;
case 113:
if ((GetRace() == 456) ||(GetRace() == 48))
return true;
break;
case 114:
if (GetRace() == 526)
return true;
break;
case 115:
if (GetRace() == 522)
return true;
break;
case 117:
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Plant))
return true;
break;
case 118:
if (GetBodyType() == BT_Summoned)
return true;
break;
case 119:
if (IsPet() && ((GetRace() == 212) || ((GetRace() == 75) && GetTexture() == 1)))
return true;
break;
case 120:
if (GetBodyType() == BT_Undead)
return true;
break;
case 121:
if (GetBodyType() != BT_Undead)
return true;
break;
case 122:
if ((GetRace() == 473) || (GetRace() == 425))
return true;
break;
case 123:
if (GetBodyType() == BT_Humanoid)
return true;
break;
case 124:
if ((GetBodyType() == BT_Undead) && (GetHPRatio() < 10))
return true;
break;
case 125:
if ((GetRace() == 457 || GetRace() == 88) && (GetHPRatio() < 10))
return true;
break;
case 126:
if ((GetRace() == 581 || GetRace() == 69) && (GetHPRatio() < 10))
return true;
break;
case 201:
if (GetHPRatio() > 75)
return true;
break;
case 204:
if (GetHPRatio() < 20)
return true;
break;
case 216:
if (!IsEngaged())
return true;
break;
case 250:
if (GetHPRatio() < 35)
return true;
break;
case 304:
if (IsClient() &&
((GetClass() == WARRIOR) || (GetClass() == BARD) || (GetClass() == SHADOWKNIGHT) || (GetClass() == PALADIN) || (GetClass() == CLERIC)
|| (GetClass() == RANGER) || (GetClass() == SHAMAN) || (GetClass() == ROGUE) || (GetClass() == BERSERKER)))
return true;
break;
case 701:
if (!IsPet())
return true;
break;
case 818:
if (GetBodyType() == BT_Undead)
return true;
break;
case 819:
if (GetBodyType() != BT_Undead)
return true;
break;
case 842:
if (GetBodyType() == BT_Humanoid && GetLevel() <= 84)
return true;
break;
case 843:
if (GetBodyType() == BT_Humanoid && GetLevel() <= 86)
return true;
break;
case 844:
if (GetBodyType() == BT_Humanoid && GetLevel() <= 88)
return true;
break;
}
//Limit to amount of pets
if (value >= 221 && value <= 249){
int count = hate_list.SummonedPetCount(this);
for (int base2_value = 221; base2_value <= 249; ++base2_value){
if (value == base2_value){
if (count >= (base2_value - 220)){
return true;
}
}
}
}
//Limit to Body Type
if (value >= 600 && value <= 699){
if (GetBodyType() == (value - 600))
return true;
}
//Limit to Race. *Not implemented on live
if (value >= 10000 && value <= 11000){
if (GetRace() == (value - 10000))
return true;
}
} //End Damage
if (!IsDamage || UseCastRestriction) {
//Heal only if HP within specified range. [Doesn't follow a set forumla for all values...]
if (value >= 400 && value <= 408){
for (int base2_value = 400; base2_value <= 408; ++base2_value){
if (value == base2_value){
if (value == 400 && GetHPRatio() <= 25)
return true;
else if (value == base2_value){
if (GetHPRatio() > 25+((base2_value - 401)*10) && GetHPRatio() <= 35+((base2_value - 401)*10))
return true;
}
}
}
}
else if (value >= 500 && value <= 549){
for (int base2_value = 500; base2_value <= 520; ++base2_value){
if (value == base2_value){
if (GetHPRatio() < (base2_value - 500)*5)
return true;
}
}
}
else if (value == 399) {
if (GetHPRatio() > 15 && GetHPRatio() <= 25)
return true;
}
} // End Heal
return false;
}

View File

@ -1361,6 +1361,11 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id);
targetType = ST_GroupClientAndPet;
}
if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){
Message_StringID(13,SPELL_NEED_TAR);
return false;
}
switch (targetType)
{
@ -2948,8 +2953,11 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
buffs[emptyslot].numhits = spells[spell_id].numhits;
buffs[emptyslot].client = caster ? caster->IsClient() : 0;
buffs[emptyslot].persistant_buff = 0;
buffs[emptyslot].deathsaveCasterAARank = 0;
buffs[emptyslot].deathSaveSuccessChance = 0;
buffs[emptyslot].caston_x = 0;
buffs[emptyslot].caston_y = 0;
buffs[emptyslot].caston_z = 0;
buffs[emptyslot].dot_rune = 0;
buffs[emptyslot].ExtraDIChance = 0;
if (level_override > 0) {
buffs[emptyslot].UpdateClient = true;
@ -3355,7 +3363,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
}
}
// Reflect
if(TryReflectSpell(spell_id) && spelltar && !reflect && IsDetrimentalSpell(spell_id) && this != spelltar) {
if(spelltar && spelltar->TryReflectSpell(spell_id) && !reflect && IsDetrimentalSpell(spell_id) && this != spelltar) {
int reflect_chance = 0;
switch(RuleI(Spells, ReflectType))
{
@ -3402,9 +3410,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
}
}
if (spelltar && IsDetrimentalSpell(spell_id))
spelltar->CheckNumHitsRemaining(3);
// resist check - every spell can be resisted, beneficial or not
// add: ok this isn't true, eqlive's spell data is fucked up, buffs are
// not all unresistable, so changing this to only check certain spells
@ -3438,6 +3443,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
}
}
spelltar->CheckNumHitsRemaining(3);
safe_delete(action_packet);
return false;
}
@ -3575,7 +3582,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
safe_delete(action_packet);
return false;
}
// cause the effects to the target
if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness))
{
@ -3588,6 +3595,10 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
return false;
}
if (spelltar && IsDetrimentalSpell(spell_id))
spelltar->CheckNumHitsRemaining(3); //Incoming spells
// send the action packet again now that the spell is successful
// NOTE: this is what causes the buff icon to appear on the client, if
// this is a buff - but it sortof relies on the first packet.
@ -4816,7 +4827,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) {
return false;
}
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) {
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id) {
if(spell_id == SPELL_UNKNOWN)
return(false);
@ -4826,7 +4837,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) {
if (PermaProcs[i].spellID == SPELL_UNKNOWN) {
PermaProcs[i].spellID = spell_id;
PermaProcs[i].chance = iChance;
PermaProcs[i].base_spellID = SPELL_UNKNOWN;
PermaProcs[i].base_spellID = base_spell_id;
mlog(SPELLS__PROCS, "Added permanent proc spell %d with chance %d to slot %d", spell_id, iChance, i);
return true;
@ -4838,7 +4849,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) {
if (SpellProcs[i].spellID == SPELL_UNKNOWN) {
SpellProcs[i].spellID = spell_id;
SpellProcs[i].chance = iChance;
SpellProcs[i].base_spellID = SPELL_UNKNOWN;;
SpellProcs[i].base_spellID = base_spell_id;;
mlog(SPELLS__PROCS, "Added spell-granted proc spell %d with chance %d to slot %d", spell_id, iChance, i);
return true;
}

View File

@ -1815,7 +1815,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO merc_buffs (MercId, SpellId, CasterLevel, DurationFormula, "
"TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, "
"DeathSaveSuccessChance, CasterAARank, Persistent) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);",
"dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);",
merc->GetMercID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula,
buffs[BuffCount].ticsremaining,
CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
@ -1823,8 +1823,12 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
CalculateCurseCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune,
buffs[BuffCount].deathSaveSuccessChance,
buffs[BuffCount].deathsaveCasterAARank, IsPersistent), TempErrorMessageBuffer)) {
buffs[BuffCount].dot_rune,
buffs[BuffCount].caston_x,
IsPersistent,
buffs[BuffCount].caston_y,
buffs[BuffCount].caston_z,
buffs[BuffCount].ExtraDIChance), TempErrorMessageBuffer)) {
errorMessage = std::string(TempErrorMessageBuffer);
safe_delete(Query);
Query = 0;
@ -1856,7 +1860,7 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
bool BuffsLoaded = false;
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) {
errorMessage = std::string(TempErrorMessageBuffer);
}
else {
@ -1882,8 +1886,8 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
buffs[BuffCount].numhits = atoi(DataRow[8]);
buffs[BuffCount].melee_rune = atoi(DataRow[9]);
buffs[BuffCount].magic_rune = atoi(DataRow[10]);
buffs[BuffCount].deathSaveSuccessChance = atoi(DataRow[11]);
buffs[BuffCount].deathsaveCasterAARank = atoi(DataRow[12]);
buffs[BuffCount].dot_rune = atoi(DataRow[11]);
buffs[BuffCount].caston_x = atoi(DataRow[12]);
buffs[BuffCount].casterid = 0;
bool IsPersistent = false;
@ -1891,6 +1895,10 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
if(atoi(DataRow[13]))
IsPersistent = true;
buffs[BuffCount].caston_y = atoi(DataRow[13]);
buffs[BuffCount].caston_z = atoi(DataRow[14]);
buffs[BuffCount].ExtraDIChance = atoi(DataRow[15]);
buffs[BuffCount].persistant_buff = IsPersistent;
BuffCount++;
@ -2484,9 +2492,9 @@ void ZoneDatabase::ListAllInstances(Client* c, uint32 charid)
MYSQL_ROW row;
if (RunQuery(query,MakeAnyLenString(&query, "SELECT instance_lockout.id, zone, version FROM instance_lockout JOIN"
" instance_lockout_player ON instance_lockout.id = instance_lockout_player.id"
" WHERE instance_lockout_player.charid=%lu", (unsigned long)charid),errbuf,&result))
if (RunQuery(query,MakeAnyLenString(&query, "SELECT instance_list.id, zone, version FROM instance_list JOIN"
" instance_list_player ON instance_list.id = instance_list_player.id"
" WHERE instance_list_player.charid=%lu", (unsigned long)charid),errbuf,&result))
{
safe_delete_array(query);
@ -2566,11 +2574,11 @@ void ZoneDatabase::SaveBuffs(Client *c) {
for (int i = 0; i < buff_count; i++) {
if(buffs[i].spellid != SPELL_UNKNOWN) {
if(!database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `character_buffs` (character_id, slot_id, spell_id, "
"caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, magic_rune, persistent, death_save_chance, "
"death_save_aa_chance) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')",
"caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, magic_rune, persistent, dot_rune, "
"caston_x, caston_y, caston_z, ExtraDIChance) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%i', '%i', '%i', '%i')",
c->CharacterID(), i, buffs[i].spellid, buffs[i].casterlevel, buffs[i].caster_name, buffs[i].ticsremaining,
buffs[i].counters, buffs[i].numhits, buffs[i].melee_rune, buffs[i].magic_rune, buffs[i].persistant_buff,
buffs[i].deathSaveSuccessChance, buffs[i].deathsaveCasterAARank),
buffs[i].dot_rune, buffs[i].caston_x, buffs[i].caston_y, buffs[i].caston_z, buffs[i].ExtraDIChance),
errbuf)) {
LogFile->write(EQEMuLog::Error, "Error in SaveBuffs query '%s': %s", query, errbuf);
}
@ -2592,7 +2600,7 @@ void ZoneDatabase::LoadBuffs(Client *c) {
MYSQL_RES *result;
MYSQL_ROW row;
if (RunQuery(query, MakeAnyLenString(&query, "SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, counters, "
"numhits, melee_rune, magic_rune, persistent, death_save_chance, death_save_aa_chance FROM `character_buffs` WHERE "
"numhits, melee_rune, magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance FROM `character_buffs` WHERE "
"`character_id`='%u'",
c->CharacterID()), errbuf, &result))
{
@ -2617,8 +2625,11 @@ void ZoneDatabase::LoadBuffs(Client *c) {
uint32 melee_rune = atoul(row[7]);
uint32 magic_rune = atoul(row[8]);
uint8 persistent = atoul(row[9]);
uint32 death_save_chance = atoul(row[10]);
uint32 death_save_aa_chance = atoul(row[11]);
uint32 dot_rune = atoul(row[10]);
int32 caston_x = atoul(row[11]);
int32 caston_y = atoul(row[12]);
int32 caston_z = atoul(row[13]);
int32 ExtraDIChance = atoul(row[14]);
buffs[slot_id].spellid = spell_id;
buffs[slot_id].casterlevel = caster_level;
@ -2638,8 +2649,11 @@ void ZoneDatabase::LoadBuffs(Client *c) {
buffs[slot_id].melee_rune = melee_rune;
buffs[slot_id].magic_rune = magic_rune;
buffs[slot_id].persistant_buff = persistent ? true : false;
buffs[slot_id].deathSaveSuccessChance = death_save_chance;
buffs[slot_id].deathsaveCasterAARank = death_save_aa_chance;
buffs[slot_id].dot_rune = dot_rune;
buffs[slot_id].caston_x = caston_x;
buffs[slot_id].caston_y = caston_y;
buffs[slot_id].caston_z = caston_z;
buffs[slot_id].ExtraDIChance = ExtraDIChance;
buffs[slot_id].UpdateClient = false;
if(IsRuneSpell(spell_id)) {
c->SetHasRune(true);
@ -2648,11 +2662,6 @@ void ZoneDatabase::LoadBuffs(Client *c) {
c->SetHasSpellRune(true);
}
/*
if(IsDeathSaveSpell(spell_id)) {
c->SetDeathSaveChance(true);
}
*/
}
mysql_free_result(result);
}