diff --git a/changelog.txt b/changelog.txt index 869ff369c..0e5a15763 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,12 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 05/07/2014 == +Kayen: AA/Item/Spells that allow pets to critical and flurry will now work on the owners swarm pets consistent with live. + +== 05/05/2014 == +Uleat: Oops! Wrong state check (conn_state != client_state) +Uleat: Test fix to eliminate seemingly random crashes when an AE spell is being used. (Possible access to uninstantiated pointers during client connection process when someone casts a beneficial AE spell within range of a connecting client.) + == 04/29/2014 == KLS: Implemented new map code based on some of Derision's earlier work. Old maps still work with this system and don't need to be regenerated. We're still working on a new azone solution for better/more efficient maps. diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 2b55e87e1..d3384da7f 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -2011,7 +2011,7 @@ void SharedDatabase::LoadLootDrops(void *data, uint32 size) { current_id = id; } - if(current_entry > 1260) { + if(current_entry >= 1260) { continue; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aef5124c9..aba365486 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,9 +32,9 @@ IF(UNIX) TARGET_LINK_LIBRARIES(tests "${CMAKE_DL_LIBS}") TARGET_LINK_LIBRARIES(tests "z") TARGET_LINK_LIBRARIES(tests "m") - IF(NOT DARWIN) - TARGET_LINK_LIBRARIES(loginserver "rt") - ENDIF(NOT DARWIN) + IF(NOT DARWIN) + TARGET_LINK_LIBRARIES(tests "rt") + ENDIF(NOT DARWIN) TARGET_LINK_LIBRARIES(tests "pthread") ADD_DEFINITIONS(-fPIC) ENDIF(UNIX) diff --git a/utils/sql/git/required/2014_04_12_SlowMitigation.sql b/utils/sql/git/required/2014_04_12_SlowMitigation.sql index f2ac0d68d..a497a525b 100644 --- a/utils/sql/git/required/2014_04_12_SlowMitigation.sql +++ b/utils/sql/git/required/2014_04_12_SlowMitigation.sql @@ -2,6 +2,6 @@ UPDATE npc_types SET slow_mitigation = slow_mitigation * 100; -- Change variable type from FLOAT TO INT -ALTER TABLE npc_types MODIFY slow_mitigation smallint(4); +ALTER TABLE npc_types MODIFY slow_mitigation smallint(4) NOT NULL DEFAULT '0'; diff --git a/utils/sql/git/required/2014_05_04_SlowMitigationFix.sql b/utils/sql/git/required/2014_05_04_SlowMitigationFix.sql new file mode 100644 index 000000000..bf657023c --- /dev/null +++ b/utils/sql/git/required/2014_05_04_SlowMitigationFix.sql @@ -0,0 +1,3 @@ +ALTER TABLE npc_types MODIFY slow_mitigation smallint(4) NOT NULL DEFAULT '0'; + + diff --git a/zone/AA.cpp b/zone/AA.cpp index 87463247b..8566c09b5 100644 --- a/zone/AA.cpp +++ b/zone/AA.cpp @@ -1358,7 +1358,7 @@ void Client::SendAA(uint32 id, int seq) { if (aa_stack){ - if (saa->sof_current_level > 1 && value == 0) + if (saa->sof_current_level >= 1 && value == 0) saa->current_level = saa->sof_current_level+1; saa->max_level = saa->sof_max_level; diff --git a/zone/MobAI.cpp b/zone/MobAI.cpp index aa791318a..88c0309c0 100644 --- a/zone/MobAI.cpp +++ b/zone/MobAI.cpp @@ -1213,11 +1213,18 @@ void Mob::AI_Process() { } } - if (IsPet()) { - Mob *owner = GetOwner(); + if (IsPet() || (IsNPC() && CastToNPC()->GetSwarmOwner())) { + Mob *owner = nullptr; + + if (IsPet()) + owner = GetOwner(); + else + owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner()); + if (owner) { int16 flurry_chance = owner->aabonuses.PetFlurry + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; + if (flurry_chance && (MakeRandomInt(0, 99) < flurry_chance)) Flurry(nullptr); } diff --git a/zone/attack.cpp b/zone/attack.cpp index 81922c126..d536c9844 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4226,11 +4226,13 @@ void Mob::TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage) if (damage < 1) //We can't critical hit if we don't hit. return; - if (!IsPet()) + if (IsPet()) + owner = GetOwner(); + else if ((IsNPC() && CastToNPC()->GetSwarmOwner())) + owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner()); + else return; - owner = GetOwner(); - if (!owner) return; @@ -4267,7 +4269,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack // decided to branch this into it's own function since it's going to be duplicating a lot of the // code in here, but could lead to some confusion otherwise - if (IsPet() && GetOwner()->IsClient()) { + if (IsPet() && GetOwner()->IsClient() || (IsNPC() && CastToNPC()->GetSwarmOwner())) { TryPetCriticalHit(defender,skill,damage); return; } @@ -4456,6 +4458,7 @@ void Mob::DoRiposte(Mob* defender) { //Double Riposte effect, allows for a chance to do RIPOSTE with a skill specfic special attack (ie Return Kick). //Coded narrowly: Limit to one per client. Limit AA only. [1 = Skill Attack Chance, 2 = Skill] + DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[1]; if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 81465f2f6..e45976e85 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1328,7 +1328,7 @@ void Client::Handle_OP_AutoAttack(const EQApplicationPacket *app) aa_los_them.y = aa_los_them_mob->GetY(); aa_los_them.z = aa_los_them_mob->GetZ(); los_status = CheckLosFN(aa_los_them_mob); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } else { diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 4a4618045..81cd55972 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -361,13 +361,13 @@ bool Client::Process() { aa_los_them.z = aa_los_them_mob->GetZ(); los_status = CheckLosFN(auto_attack_target); aa_los_me_heading = GetHeading(); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } // If only our heading changes, we can skip the CheckLosFN call // but above we still need to update los_status_facing if (aa_los_me_heading != GetHeading()) { aa_los_me_heading = GetHeading(); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } } else @@ -381,7 +381,7 @@ bool Client::Process() { aa_los_them.y = aa_los_them_mob->GetY(); aa_los_them.z = aa_los_them_mob->GetZ(); los_status = CheckLosFN(auto_attack_target); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } if (!CombatRange(auto_attack_target)) diff --git a/zone/effects.cpp b/zone/effects.cpp index cbe914524..58b06a68e 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -748,6 +748,9 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { curmob = it->second; + // test to fix possible cause of random zone crashes..external methods accessing client properties before they're initialized + if (curmob->IsClient() && !curmob->CastToClient()->ClientFinishedLoading()) + continue; if (curmob == center) //do not affect center continue; if (curmob == caster && !affect_caster) //watch for caster too diff --git a/zone/mob.cpp b/zone/mob.cpp index 79ebebde6..e087e2447 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -5046,3 +5046,54 @@ void Mob::ProcessSpecialAbilities(const std::string str) { } } } + +// derived from client to keep these functions more consistent +// if anything seems weird, blame SoE +bool Mob::IsFacingMob(Mob *other) +{ + if (!other) + return false; + float angle = HeadingAngleToMob(other); + // what the client uses appears to be 2x our internal heading + float heading = GetHeading() * 2.0; + + if (angle > 472.0 && heading < 40.0) + angle = heading; + if (angle < 40.0 && heading > 472.0) + angle = heading; + + if (fabs(angle - heading) <= 80.0) + return true; + + return false; +} + +// All numbers derived from the client +float Mob::HeadingAngleToMob(Mob *other) +{ + float mob_x = other->GetX(); + float mob_y = other->GetY(); + float this_x = GetX(); + float this_y = GetY(); + + float y_diff = fabs(this_y - mob_y); + float x_diff = fabs(this_x - mob_x); + if (y_diff < 0.0000009999999974752427) + y_diff = 0.0000009999999974752427; + + float angle = atan2(x_diff, y_diff) * 180.0 * 0.3183099014828645; // angle, nice "pi" + + // return the right thing based on relative quadrant + // I'm sure this could be improved for readability, but whatever + if (this_y >= mob_y) { + if (mob_x >= this_x) + return (90.0 - angle + 90.0) * 511.5 * 0.0027777778; + if (mob_x <= this_x) + return (angle + 180.0) * 511.5 * 0.0027777778; + } + if (this_y > mob_y || mob_x > this_x) + return angle * 511.5 * 0.0027777778; + else + return (90.0 - angle + 270.0) * 511.5 * 0.0027777778; +} + diff --git a/zone/mob.h b/zone/mob.h index c2aa00814..f4b89a754 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -125,6 +125,8 @@ public: // less than 56 is in front, greater than 56 is usually where the client generates the messages inline bool InFrontMob(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const { return (!other || other == this) ? true : MobAngle(other, ourx, oury) < 56.0f; } + bool IsFacingMob(Mob *other); // kind of does the same as InFrontMob, but derived from client + float HeadingAngleToMob(Mob *other); // to keep consistent with client generated messages virtual void RangedAttack(Mob* other) { } virtual void ThrowingAttack(Mob* other) { } uint16 GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg);