diff --git a/changelog.txt b/changelog.txt index f5b75ff98..058e05542 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- + +== 11/09/2014 == +Kayen: Implemented support for spell target type (45) 'Target Rings' on Underfoot (does work earlier expansions) +Thanks to Lecht for figuring out the op_code side. + == 11/06/2014 == demonstar55: Tracking default sort will now be correct order Trevius: Fixed dynamic merchant list loading. Allows any merchant to be used in any zone. diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index a5e22e44e..0630ce293 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -478,7 +478,11 @@ struct CastSpell_Struct uint32 spell_id; uint32 inventoryslot; // slot for clicky item, 0xFFFF = normal cast uint32 target_id; - uint8 cs_unknown[4]; + uint32 cs_unknown1; + uint32 cs_unknown2; + float y_pos; + float x_pos; + float z_pos; }; struct SpellEffect_Struct diff --git a/common/patches/underfoot.cpp b/common/patches/underfoot.cpp index f5049d77f..78bdb5f2e 100644 --- a/common/patches/underfoot.cpp +++ b/common/patches/underfoot.cpp @@ -2994,6 +2994,11 @@ namespace Underfoot IN(spell_id); emu->inventoryslot = UnderfootToServerSlot(eq->inventoryslot); IN(target_id); + IN(cs_unknown1); + IN(cs_unknown2); + IN(y_pos); + IN(x_pos); + IN(z_pos); FINISH_DIRECT_DECODE(); } diff --git a/common/patches/underfoot_structs.h b/common/patches/underfoot_structs.h index 0b17412f6..ebad98678 100644 --- a/common/patches/underfoot_structs.h +++ b/common/patches/underfoot_structs.h @@ -519,7 +519,11 @@ struct CastSpell_Struct uint32 spell_id; uint32 inventoryslot; // slot for clicky item, 0xFFFF = normal cast uint32 target_id; - uint32 cs_unknown[5]; + uint32 cs_unknown1; + uint32 cs_unknown2; + float y_pos; + float x_pos; + float z_pos; }; /* diff --git a/common/spdat.h b/common/spdat.h index 2dfc016b4..feaddaf84 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -132,7 +132,7 @@ typedef enum { /* 42 */ ST_Directional = 0x2a, //ae around this target between two angles /* 43 */ ST_GroupClientAndPet = 0x2b, /* 44 */ //ST_Beam = 0x2c, //like directional but facing in front of you always -/* 45 */ //ST_Ring = 0x2d, // Like a mix of PB ae + rain spell(has ae duration) +/* 45 */ ST_Ring = 0x2d, /* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target /* 47 */ ST_PetMaster = 0x2f, // uses the master as target } SpellTargetType; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 29b2b91be..73a5c79c9 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -4034,6 +4034,10 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) return; } + targetring_x = castspell->x_pos; + targetring_y = castspell->y_pos; + targetring_z = castspell->z_pos; + CastSpell(spell_to_cast, castspell->target_id, castspell->slot); } /* Spell Slot or Potion Belt Slot */ diff --git a/zone/common.h b/zone/common.h index 436cd6699..8b6464268 100644 --- a/zone/common.h +++ b/zone/common.h @@ -494,6 +494,7 @@ typedef enum { GroupSpell, // causes effect to caster + target's group CAHateList, // causes effect to all people on caster's hate list within some range DirectionalAE, + TargetRing, CastActUnknown } CastAction_type; diff --git a/zone/effects.cpp b/zone/effects.cpp index 90b9c0c4c..e5c631aaa 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -764,8 +764,14 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ continue; if (curmob == caster && !affect_caster) //watch for caster too continue; - - dist_targ = center->DistNoRoot(*curmob); + + if (spells[spell_id].targettype == ST_Ring){ + dist_targ = curmob->DistNoRoot(caster->GetTargetRingX(), caster->GetTargetRingY(),caster->GetTargetRingZ()); + } + else if (center){ + dist_targ = center->DistNoRoot(*curmob); + } + if (dist_targ > dist2) //make sure they are in range continue; if (dist_targ < min_range2) //make sure they are in range @@ -787,7 +793,9 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ if (bad) { if (!caster->IsAttackAllowed(curmob, true)) continue; - if (!center->CheckLosFN(curmob)) + if (center && !center->CheckLosFN(curmob)) + continue; + if (!center && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(),caster->GetTargetRingZ(), curmob->GetSize())) continue; } else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies... // This does not check faction for beneficial AE buffs..only agro and attackable. diff --git a/zone/mob.cpp b/zone/mob.cpp index 7e277d438..d0f973a5a 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -369,6 +369,10 @@ Mob::Mob(const char* in_name, nimbus_effect3 = 0; m_targetable = true; + targetring_x = 0.0f; + targetring_y = 0.0f; + targetring_z = 0.0f; + flymode = FlyMode3; // Pathing PathingLOSState = UnknownLOS; diff --git a/zone/mob.h b/zone/mob.h index ec25aff20..6e11c8cfb 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -287,6 +287,9 @@ public: inline virtual uint32 GetNimbusEffect2() const { return nimbus_effect2; } inline virtual uint32 GetNimbusEffect3() const { return nimbus_effect3; } void RemoveNimbusEffect(int effectid); + inline float GetTargetRingX() const { return targetring_x; } + inline float GetTargetRingY() const { return targetring_y; } + inline float GetTargetRingZ() const { return targetring_z; } //Basic Stats/Inventory virtual void SetLevel(uint8 in_level, bool command = false) { level = in_level; } @@ -1231,6 +1234,10 @@ protected: float tar_vz; float test_vector; + float targetring_x; + float targetring_y; + float targetring_z; + uint32 m_spellHitsLeft[38]; // Used to track which spells will have their numhits incremented when spell finishes casting, 38 Buffslots int flymode; bool m_targetable; diff --git a/zone/spells.cpp b/zone/spells.cpp index 8ede6aa66..4a4429194 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -368,6 +368,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, if((IsGroupSpell(spell_id) || spell.targettype == ST_Self || spell.targettype == ST_AECaster || + spell.targettype == ST_Ring || spell.targettype == ST_TargetOptional) && target_id == 0) { mlog(SPELLS__CASTING, "Spell %d auto-targeted the caster. Group? %d, target type %d", spell_id, IsGroupSpell(spell_id), spell.targettype); @@ -1802,6 +1803,14 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce break; } + case ST_Ring: + { + CastAction = TargetRing; + spell_target = nullptr; + ae_center = nullptr; + break; + } + default: { mlog(SPELLS__CASTING_ERR, "I dont know Target Type: %d Spell: (%d) %s", spells[spell_id].targettype, spell_id, spells[spell_id].name); @@ -2165,6 +2174,11 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } break; } + + case TargetRing:{ + entity_list.AESpell(this, nullptr, spell_id, false, resist_adjust); + break; + } } DoAnim(spells[spell_id].CastingAnim, 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);