mirror of
https://github.com/EQEmu/Server.git
synced 2026-01-28 10:33:52 +00:00
Merge pull request #290 from KayenEQ/Development
Implemented target type (44) Beams
This commit is contained in:
commit
8c8cec29d4
@ -1,6 +1,12 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
|
||||
== 11/13/2014 ==
|
||||
Kayen: Implemented target type (44) 'Beams' (which projects an AE infront of caster with a specified length and width).
|
||||
Kayen: Implemented target type (32) AE Target HateList
|
||||
Kayen: Implemented target type (36) Area Client Only
|
||||
Kayen: Implemented target type (37) Area PC Only
|
||||
Kayen: Implemented target type (39) Group No Pet
|
||||
Uleat: PlayerLogMerchantTransactions does not support partial stack purchase logging at this time
|
||||
|
||||
== 11/12/2014 ==
|
||||
|
||||
@ -1564,6 +1564,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
sp[tempid].NimbusEffect = atoi(row[193]);
|
||||
sp[tempid].directional_start = static_cast<float>(atoi(row[194]));
|
||||
sp[tempid].directional_end = static_cast<float>(atoi(row[195]));
|
||||
sp[tempid].sneak = atoi(row[196]) != 0;
|
||||
sp[tempid].not_extendable = atoi(row[197]) != 0;
|
||||
sp[tempid].suspendable = atoi(row[200]) != 0;
|
||||
sp[tempid].viral_range = atoi(row[201]);
|
||||
|
||||
@ -119,7 +119,7 @@ typedef enum {
|
||||
/* 29 */ // NOT USED
|
||||
/* 30 */ // NOT USED
|
||||
/* 31 */ // NOT USED
|
||||
/* 32 */ ST_AECaster2 = 0x20, //ae caster hatelist maybe?
|
||||
/* 32 */ ST_AETargetHateList = 0x20,
|
||||
/* 33 */ ST_HateList = 0x21,
|
||||
/* 34 */ ST_LDoNChest_Cursed = 0x22,
|
||||
/* 35 */ ST_Muramite = 0x23, //only works on special muramites
|
||||
@ -131,10 +131,13 @@ typedef enum {
|
||||
/* 41 */ ST_Group = 0x29,
|
||||
/* 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
|
||||
/* 44 */ ST_Beam = 0x2c,
|
||||
/* 45 */ ST_Ring = 0x2d,
|
||||
/* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target
|
||||
/* 47 */ ST_PetMaster = 0x2f, // uses the master as target
|
||||
/* 48 */ // UNKNOWN
|
||||
/* 49 */ // NOT USED
|
||||
/* 50 */ ST_TargetAENoPlayersPets = 0x32,
|
||||
} SpellTargetType;
|
||||
|
||||
typedef enum {
|
||||
@ -719,7 +722,7 @@ struct SPDat_Spell_Struct
|
||||
/* 193 */ int NimbusEffect;
|
||||
/* 194 */ float directional_start; //Cone Start Angle:
|
||||
/* 195 */ float directional_end; // Cone End Angle:
|
||||
/* 196 */
|
||||
/* 196 */ bool sneak; // effect can only be used if sneaking (rogue 'Daggerfall' ect)
|
||||
/* 197 */ bool not_extendable;
|
||||
/* 198- 199 */
|
||||
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones
|
||||
|
||||
@ -495,6 +495,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,
|
||||
Beam,
|
||||
TargetRing,
|
||||
CastActUnknown
|
||||
} CastAction_type;
|
||||
|
||||
@ -752,7 +752,11 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
|
||||
bool bad = IsDetrimentalSpell(spell_id);
|
||||
bool isnpc = caster->IsNPC();
|
||||
const int MAX_TARGETS_ALLOWED = 4;
|
||||
int MAX_TARGETS_ALLOWED = 4;
|
||||
|
||||
if (spells[spell_id].aemaxtargets)
|
||||
MAX_TARGETS_ALLOWED = spells[spell_id].aemaxtargets;
|
||||
|
||||
int iCounter = 0;
|
||||
|
||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||
@ -764,6 +768,12 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
continue;
|
||||
if (curmob == caster && !affect_caster) //watch for caster too
|
||||
continue;
|
||||
if (spells[spell_id].targettype == ST_TargetAENoPlayersPets && curmob->IsPetOwnerClient())
|
||||
continue;
|
||||
if (spells[spell_id].targettype == ST_AreaClientOnly && !curmob->IsClient())
|
||||
continue;
|
||||
if (spells[spell_id].targettype == ST_AreaNPCOnly && !curmob->IsNPC())
|
||||
continue;
|
||||
|
||||
if (spells[spell_id].targettype == ST_Ring) {
|
||||
dist_targ = curmob->DistNoRoot(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ());
|
||||
@ -815,10 +825,13 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
}
|
||||
} else {
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets)
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
if (!spells[spell_id].aemaxtargets)
|
||||
caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust);
|
||||
}
|
||||
|
||||
if (!isnpc) //npcs are not target limited...
|
||||
if (!isnpc || spells[spell_id].aemaxtargets) //npcs are not target limited (unless casting a spell with a target limit)...
|
||||
iCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -693,7 +693,7 @@ void Group::CastGroupSpell(Mob* caster, uint16 spell_id) {
|
||||
if(members[z] == caster) {
|
||||
caster->SpellOnTarget(spell_id, caster);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if(caster->GetPet() && caster->HasPetAffinity() && !caster->GetPet()->IsCharmed())
|
||||
if(spells[spell_id].targettype != ST_GroupNoPets && caster->GetPet() && caster->HasPetAffinity() && !caster->GetPet()->IsCharmed())
|
||||
caster->SpellOnTarget(spell_id, caster->GetPet());
|
||||
#endif
|
||||
}
|
||||
@ -704,7 +704,7 @@ void Group::CastGroupSpell(Mob* caster, uint16 spell_id) {
|
||||
members[z]->CalcSpellPowerDistanceMod(spell_id, distance);
|
||||
caster->SpellOnTarget(spell_id, members[z]);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if(members[z]->GetPet() && members[z]->HasPetAffinity() && !members[z]->GetPet()->IsCharmed())
|
||||
if(spells[spell_id].targettype != ST_GroupNoPets && members[z]->GetPet() && members[z]->HasPetAffinity() && !members[z]->GetPet()->IsCharmed())
|
||||
caster->SpellOnTarget(spell_id, members[z]->GetPet());
|
||||
#endif
|
||||
} else
|
||||
|
||||
@ -557,12 +557,15 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HateList::SpellCast(Mob *caster, uint32 spell_id, float range)
|
||||
void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_center)
|
||||
{
|
||||
if(!caster)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mob* center = caster;
|
||||
|
||||
if (ae_center)
|
||||
center = ae_center;
|
||||
|
||||
//this is slower than just iterating through the list but avoids
|
||||
//crashes when people kick the bucket in the middle of this call
|
||||
@ -578,7 +581,7 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range)
|
||||
tHateEntry *h = (*iterator);
|
||||
if(range > 0)
|
||||
{
|
||||
dist_targ = caster->DistNoRoot(*h->ent);
|
||||
dist_targ = center->DistNoRoot(*h->ent);
|
||||
if(dist_targ <= range && dist_targ >= min_range2)
|
||||
{
|
||||
id_list.push_back(h->ent->GetID());
|
||||
|
||||
@ -63,7 +63,7 @@ public:
|
||||
|
||||
int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts);
|
||||
|
||||
void SpellCast(Mob *caster, uint32 spell_id, float range);
|
||||
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
|
||||
|
||||
bool IsEmpty();
|
||||
void PrintToClient(Client *c);
|
||||
|
||||
@ -300,6 +300,8 @@ Mob::Mob(const char* in_name,
|
||||
held = false;
|
||||
nocast = false;
|
||||
focused = false;
|
||||
_IsTempPet = false;
|
||||
pet_owner_client = false;
|
||||
|
||||
attacked_count = 0;
|
||||
mezzed = false;
|
||||
|
||||
10
zone/mob.h
10
zone/mob.h
@ -235,7 +235,9 @@ public:
|
||||
void ResourceTap(int32 damage, uint16 spell_id);
|
||||
void TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker);
|
||||
bool CheckSpellCategory(uint16 spell_id, int category_id, int effect_id);
|
||||
|
||||
void CalcDestFromHeading(float heading, float distance, float MaxZDiff, float StartX, float StartY, float &dX, float &dY, float &dZ);
|
||||
void BeamDirectional(uint16 spell_id, int16 resist_adjust);
|
||||
void ConeDirectional(uint16 spell_id, int16 resist_adjust);
|
||||
|
||||
//Buff
|
||||
void BuffProcess();
|
||||
@ -674,6 +676,10 @@ public:
|
||||
bool HadTempPets() const { return(hasTempPet); }
|
||||
void TempPets(bool i) { hasTempPet = i; }
|
||||
bool HasPetAffinity() { if (aabonuses.GivePetGroupTarget || itembonuses.GivePetGroupTarget || spellbonuses.GivePetGroupTarget) return true; return false; }
|
||||
inline bool IsPetOwnerClient() const { return pet_owner_client; }
|
||||
inline void SetPetOwnerClient(bool value) { pet_owner_client = value; }
|
||||
inline bool IsTempPet() const { return _IsTempPet; }
|
||||
inline void SetTempPet(bool value) { _IsTempPet = value; }
|
||||
|
||||
inline const bodyType GetBodyType() const { return bodytype; }
|
||||
inline const bodyType GetOrigBodyType() const { return orig_bodytype; }
|
||||
@ -1225,6 +1231,8 @@ protected:
|
||||
|
||||
//temppet
|
||||
bool hasTempPet;
|
||||
bool _IsTempPet;
|
||||
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
||||
|
||||
EGNode *_egnode; //the EG node we are in
|
||||
float tarx;
|
||||
|
||||
13
zone/npc.cpp
13
zone/npc.cpp
@ -1847,6 +1847,7 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
Client *c = entity_list.GetClientByID(GetSwarmOwner());
|
||||
if(c) {
|
||||
SetAllowBeneficial(1); //Allow client cast swarm pets to be heal/buffed.
|
||||
SetPetOwnerClient(true);
|
||||
//This is a hack to allow CLIENT swarm pets NOT to be targeted with F8. Warning: Will turn name 'Yellow'!
|
||||
if (RuleB(Pets, SwarmPetNotTargetableWithHotKey))
|
||||
ns->spawn.IsMercenary = 1;
|
||||
@ -1862,16 +1863,20 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.is_pet = 1;
|
||||
if (!IsCharmed() && GetOwnerID()) {
|
||||
Client *c = entity_list.GetClientByID(GetOwnerID());
|
||||
if(c)
|
||||
if(c){
|
||||
SetPetOwnerClient(true);
|
||||
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
||||
}
|
||||
}
|
||||
else if (GetSwarmOwner()) {
|
||||
ns->spawn.bodytype = 11;
|
||||
if(!IsCharmed())
|
||||
{
|
||||
Client *c = entity_list.GetClientByID(GetSwarmOwner());
|
||||
if(c)
|
||||
if(c){
|
||||
SetPetOwnerClient(true);
|
||||
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1880,8 +1885,10 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
ns->spawn.is_pet = 1;
|
||||
if (!IsCharmed() && GetOwnerID()) {
|
||||
Client *c = entity_list.GetClientByID(GetOwnerID());
|
||||
if(c)
|
||||
if(c){
|
||||
SetPetOwnerClient(true);
|
||||
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
||||
}
|
||||
}
|
||||
} else
|
||||
ns->spawn.is_pet = 0;
|
||||
|
||||
@ -478,7 +478,7 @@ void Raid::CastGroupSpell(Mob* caster, uint16 spellid, uint32 gid)
|
||||
if(members[x].member == caster) {
|
||||
caster->SpellOnTarget(spellid, caster);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if(caster->GetPet() && caster->HasPetAffinity() && !caster->GetPet()->IsCharmed())
|
||||
if(spells[spellid].targettype != ST_GroupNoPets && caster->GetPet() && caster->HasPetAffinity() && !caster->GetPet()->IsCharmed())
|
||||
caster->SpellOnTarget(spellid, caster->GetPet());
|
||||
#endif
|
||||
}
|
||||
@ -489,7 +489,7 @@ void Raid::CastGroupSpell(Mob* caster, uint16 spellid, uint32 gid)
|
||||
if(distance <= range2){
|
||||
caster->SpellOnTarget(spellid, members[x].member);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if(members[x].member->GetPet() && members[x].member->HasPetAffinity() && !members[x].member->GetPet()->IsCharmed())
|
||||
if(spells[spellid].targettype != ST_GroupNoPets && members[x].member->GetPet() && members[x].member->HasPetAffinity() && !members[x].member->GetPet()->IsCharmed())
|
||||
caster->SpellOnTarget(spellid, members[x].member->GetPet());
|
||||
#endif
|
||||
}
|
||||
|
||||
268
zone/spells.cpp
268
zone/spells.cpp
@ -369,6 +369,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
spell.targettype == ST_Self ||
|
||||
spell.targettype == ST_AECaster ||
|
||||
spell.targettype == ST_Ring ||
|
||||
spell.targettype == ST_Beam ||
|
||||
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);
|
||||
@ -1610,9 +1611,48 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_AETargetHateList:
|
||||
{
|
||||
if (spells[spell_id].range > 0)
|
||||
{
|
||||
if(!spell_target)
|
||||
return false;
|
||||
|
||||
ae_center = spell_target;
|
||||
CastAction = AETarget;
|
||||
}
|
||||
else {
|
||||
spell_target = nullptr;
|
||||
ae_center = this;
|
||||
CastAction = CAHateList;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_AreaClientOnly:
|
||||
case ST_AreaNPCOnly:
|
||||
{
|
||||
if (spells[spell_id].range > 0)
|
||||
{
|
||||
if(!spell_target)
|
||||
return false;
|
||||
|
||||
ae_center = spell_target;
|
||||
CastAction = AETarget;
|
||||
}
|
||||
else {
|
||||
spell_target = nullptr;
|
||||
ae_center = this;
|
||||
CastAction = AECaster;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_UndeadAE: //should only affect undead...
|
||||
case ST_SummonedAE:
|
||||
case ST_TargetAETap:
|
||||
case ST_AETarget:
|
||||
case ST_TargetAENoPlayersPets:
|
||||
{
|
||||
if(!spell_target)
|
||||
{
|
||||
@ -1628,6 +1668,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
// Group spells
|
||||
case ST_GroupTeleport:
|
||||
case ST_Group:
|
||||
case ST_GroupNoPets:
|
||||
{
|
||||
if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id)) {
|
||||
if( (!target) ||
|
||||
@ -1803,6 +1844,14 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_Beam:
|
||||
{
|
||||
CastAction = Beam;
|
||||
spell_target = nullptr;
|
||||
ae_center = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_Ring:
|
||||
{
|
||||
CastAction = TargetRing;
|
||||
@ -2033,15 +2082,28 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
} else {
|
||||
// regular PB AE or targeted AE spell - spell_target is null if PB
|
||||
if(spell_target) // this must be an AETarget spell
|
||||
{
|
||||
{
|
||||
bool cast_on_target = true;
|
||||
if (spells[spell_id].targettype == ST_TargetAENoPlayersPets && spell_target->IsPetOwnerClient())
|
||||
cast_on_target = false;
|
||||
if (spells[spell_id].targettype == ST_AreaClientOnly && !spell_target->IsClient())
|
||||
cast_on_target = false;
|
||||
if (spells[spell_id].targettype == ST_AreaNPCOnly && !spell_target->IsNPC())
|
||||
cast_on_target = false;
|
||||
|
||||
// affect the target too
|
||||
SpellOnTarget(spell_id, spell_target, false, true, resist_adjust);
|
||||
if (cast_on_target)
|
||||
SpellOnTarget(spell_id, spell_target, false, true, resist_adjust);
|
||||
}
|
||||
if(ae_center && ae_center == this && IsBeneficialSpell(spell_id))
|
||||
SpellOnTarget(spell_id, this);
|
||||
|
||||
bool affect_caster = !IsNPC(); //NPC AE spells do not affect the NPC caster
|
||||
entity_list.AESpell(this, ae_center, spell_id, affect_caster, resist_adjust);
|
||||
|
||||
if (spells[spell_id].targettype == ST_AETargetHateList)
|
||||
hate_list.SpellCast(this, spell_id, spells[spell_id].aoerange, ae_center);
|
||||
else
|
||||
entity_list.AESpell(this, ae_center, spell_id, affect_caster, resist_adjust);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2099,7 +2161,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
SpellOnTarget(spell_id, this);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
//pet too
|
||||
if (GetPet() && HasPetAffinity() && !GetPet()->IsCharmed())
|
||||
if (spells[spell_id].targettype != ST_GroupNoPets && GetPet() && HasPetAffinity() && !GetPet()->IsCharmed())
|
||||
SpellOnTarget(spell_id, GetPet());
|
||||
#endif
|
||||
}
|
||||
@ -2107,7 +2169,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
SpellOnTarget(spell_id, spell_target);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
//pet too
|
||||
if (spell_target->GetPet() && HasPetAffinity() && !spell_target->GetPet()->IsCharmed())
|
||||
if (spells[spell_id].targettype != ST_GroupNoPets && spell_target->GetPet() && HasPetAffinity() && !spell_target->GetPet()->IsCharmed())
|
||||
SpellOnTarget(spell_id, spell_target->GetPet());
|
||||
#endif
|
||||
}
|
||||
@ -2126,54 +2188,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
|
||||
case DirectionalAE:
|
||||
{
|
||||
float angle_start = spells[spell_id].directional_start + (GetHeading() * 360.0f / 256.0f);
|
||||
float angle_end = spells[spell_id].directional_end + (GetHeading() * 360.0f / 256.0f);
|
||||
|
||||
while(angle_start > 360.0f)
|
||||
angle_start -= 360.0f;
|
||||
|
||||
while(angle_end > 360.0f)
|
||||
angle_end -= 360.0f;
|
||||
|
||||
std::list<Mob*> targets_in_range;
|
||||
std::list<Mob*>::iterator iter;
|
||||
|
||||
entity_list.GetTargetsForConeArea(this, spells[spell_id].min_range, spells[spell_id].aoerange, spells[spell_id].aoerange / 2, targets_in_range);
|
||||
iter = targets_in_range.begin();
|
||||
while(iter != targets_in_range.end())
|
||||
{
|
||||
float heading_to_target = (CalculateHeadingToTarget((*iter)->GetX(), (*iter)->GetY()) * 360.0f / 256.0f);
|
||||
while(heading_to_target < 0.0f)
|
||||
heading_to_target += 360.0f;
|
||||
|
||||
while(heading_to_target > 360.0f)
|
||||
heading_to_target -= 360.0f;
|
||||
|
||||
if(angle_start > angle_end)
|
||||
{
|
||||
if((heading_to_target >= angle_start && heading_to_target <= 360.0f) ||
|
||||
(heading_to_target >= 0.0f && heading_to_target <= angle_end))
|
||||
{
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id, (*iter), false, true, resist_adjust);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(heading_to_target >= angle_start && heading_to_target <= angle_end)
|
||||
{
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id, (*iter), false, true, resist_adjust);
|
||||
}
|
||||
}
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
ConeDirectional(spell_id, resist_adjust);
|
||||
break;
|
||||
}
|
||||
|
||||
case Beam:
|
||||
{
|
||||
BeamDirectional(spell_id, resist_adjust);
|
||||
break;
|
||||
}
|
||||
|
||||
case TargetRing:
|
||||
{
|
||||
@ -3239,6 +3262,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
if(spelltar->IsClient() && spelltar->CastToClient()->IsHoveringForRespawn())
|
||||
return false;
|
||||
|
||||
if (spells[spell_id].sneak && IsClient() && !CastToClient()->sneaking){
|
||||
Message_StringID(13, SNEAK_RESTRICT);
|
||||
return false;//Fail Safe, this can cause a zone crash certain situations if you try to apply sneak effects when not sneaking.
|
||||
}
|
||||
|
||||
if(IsDetrimentalSpell(spell_id) && !IsAttackAllowed(spelltar) && !IsResurrectionEffects(spell_id)) {
|
||||
if(!IsClient() || !CastToClient()->GetGM()) {
|
||||
Message_StringID(MT_SpellFailure, SPELL_NO_HOLD);
|
||||
@ -4688,7 +4716,7 @@ void NPC::Stun(int duration) {
|
||||
|
||||
void NPC::UnStun() {
|
||||
Mob::UnStun();
|
||||
SetRunAnimSpeed(this->GetRunspeed());
|
||||
SetRunAnimSpeed(static_cast<int8>(GetRunspeed()));
|
||||
SendPosition();
|
||||
}
|
||||
|
||||
@ -5385,3 +5413,139 @@ void Client::SendSpellAnim(uint16 targetid, uint16 spell_id)
|
||||
app.priority = 1;
|
||||
entity_list.QueueCloseClients(this, &app);
|
||||
}
|
||||
|
||||
void Mob::CalcDestFromHeading(float heading, float distance, float MaxZDiff, float StartX, float StartY, float &dX, float &dY, float &dZ)
|
||||
{
|
||||
if (!distance) { return; }
|
||||
if (!MaxZDiff) { MaxZDiff = 5; }
|
||||
|
||||
float ReverseHeading = 256 - heading;
|
||||
float ConvertAngle = ReverseHeading * 1.40625f;
|
||||
if (ConvertAngle <= 270)
|
||||
ConvertAngle = ConvertAngle + 90;
|
||||
else
|
||||
ConvertAngle = ConvertAngle - 270;
|
||||
|
||||
float Radian = ConvertAngle * (3.1415927f / 180.0f);
|
||||
|
||||
float CircleX = distance * cos(Radian);
|
||||
float CircleY = distance * sin(Radian);
|
||||
dX = CircleX + StartX;
|
||||
dY = CircleY + StartY;
|
||||
dZ = FindGroundZ(dX, dY, MaxZDiff);
|
||||
}
|
||||
|
||||
void Mob::BeamDirectional(uint16 spell_id, int16 resist_adjust)
|
||||
{
|
||||
int maxtarget_count = 0;
|
||||
bool beneficial_targets = false;
|
||||
|
||||
if (IsBeneficialSpell(spell_id) && IsClient())
|
||||
beneficial_targets = true;
|
||||
|
||||
std::list<Mob*> targets_in_range;
|
||||
std::list<Mob*>::iterator iter;
|
||||
|
||||
entity_list.GetTargetsForConeArea(this, spells[spell_id].min_range, spells[spell_id].range, spells[spell_id].range / 2, targets_in_range);
|
||||
iter = targets_in_range.begin();
|
||||
|
||||
float dX = 0;
|
||||
float dY = 0;
|
||||
float dZ = 0;
|
||||
|
||||
CalcDestFromHeading(GetHeading(), spells[spell_id].range, 5, GetX(), GetY(), dX, dY, dZ);
|
||||
dZ = GetZ();
|
||||
|
||||
//FIND SLOPE: Put it into the form y = mx + b
|
||||
float m = (dY - GetY()) / (dX - GetX());
|
||||
float b = (GetY() * dX - dY * GetX()) / (dX - GetX());
|
||||
|
||||
while(iter != targets_in_range.end())
|
||||
{
|
||||
if (!(*iter) || (beneficial_targets && ((*iter)->IsNPC() && !(*iter)->IsPetOwnerClient()))
|
||||
|| (*iter)->BehindMob(this, (*iter)->GetX(),(*iter)->GetY())){
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
//# shortest distance from line to target point
|
||||
float d = abs( (*iter)->GetY() - m * (*iter)->GetX() - b) / sqrt(m * m + 1);
|
||||
|
||||
if (d <= spells[spell_id].aoerange)
|
||||
{
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los) {
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id, (*iter), false, true, resist_adjust);
|
||||
maxtarget_count++;
|
||||
}
|
||||
|
||||
if (maxtarget_count >= spells[spell_id].aemaxtargets)
|
||||
return;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust)
|
||||
{
|
||||
int maxtarget_count = 0;
|
||||
bool beneficial_targets = false;
|
||||
|
||||
if (IsBeneficialSpell(spell_id) && IsClient())
|
||||
beneficial_targets = true;
|
||||
|
||||
float angle_start = spells[spell_id].directional_start + (GetHeading() * 360.0f / 256.0f);
|
||||
float angle_end = spells[spell_id].directional_end + (GetHeading() * 360.0f / 256.0f);
|
||||
|
||||
while(angle_start > 360.0f)
|
||||
angle_start -= 360.0f;
|
||||
|
||||
while(angle_end > 360.0f)
|
||||
angle_end -= 360.0f;
|
||||
|
||||
std::list<Mob*> targets_in_range;
|
||||
std::list<Mob*>::iterator iter;
|
||||
|
||||
entity_list.GetTargetsForConeArea(this, spells[spell_id].min_range, spells[spell_id].aoerange, spells[spell_id].aoerange / 2, targets_in_range);
|
||||
iter = targets_in_range.begin();
|
||||
|
||||
while(iter != targets_in_range.end()){
|
||||
|
||||
if (!(*iter) || (beneficial_targets && ((*iter)->IsNPC() && !(*iter)->IsPetOwnerClient()))){
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
float heading_to_target = (CalculateHeadingToTarget((*iter)->GetX(), (*iter)->GetY()) * 360.0f / 256.0f);
|
||||
|
||||
while(heading_to_target < 0.0f)
|
||||
heading_to_target += 360.0f;
|
||||
|
||||
while(heading_to_target > 360.0f)
|
||||
heading_to_target -= 360.0f;
|
||||
|
||||
if(angle_start > angle_end){
|
||||
if((heading_to_target >= angle_start && heading_to_target <= 360.0f) || (heading_to_target >= 0.0f && heading_to_target <= angle_end)){
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id,(*iter), false, true, resist_adjust);
|
||||
maxtarget_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(heading_to_target >= angle_start && heading_to_target <= angle_end){
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los) {
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id, (*iter), false, true, resist_adjust);
|
||||
maxtarget_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxtarget_count >= spells[spell_id].aemaxtargets)
|
||||
return;
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
@ -338,6 +338,7 @@
|
||||
#define STRIKETHROUGH_STRING 9078 //You strike through your opponent's defenses!
|
||||
#define SPELL_REFLECT 9082 //%1's spell has been reflected by %2.
|
||||
#define NEW_SPELLS_AVAIL 9149 //You have new spells available to you. Check the merchants near your guild master.
|
||||
#define SNEAK_RESTRICT 9240 //You can not use this ability because you have not been hidden for long enough.
|
||||
#define PET_NOW_FOCUSING 9254 //Focusing on one target, Master.
|
||||
#define PET_NOT_FOCUSING 9263 //No longer focusing on one target, Master.
|
||||
#define PET_NOT_CASTING 9264 //Not casting spells, Master.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user