mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-14 11:31:30 +00:00
Implemented target type (44) 'Beams' (which projects an AE infront of caster with a specified length and width).
Clean up of target type direction code, implemented use of aemaxtargets field for it.
This commit is contained in:
parent
16f72be898
commit
fabe93e548
@ -1,5 +1,8 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
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).
|
||||||
|
|
||||||
== 11/12/2014 ==
|
== 11/12/2014 ==
|
||||||
Uleat: Changed 'GMTrainee' struct to reflect the actual client hard-coded max skill count (100) - applies to all currently supported clients (6.2->RoF)
|
Uleat: Changed 'GMTrainee' struct to reflect the actual client hard-coded max skill count (100) - applies to all currently supported clients (6.2->RoF)
|
||||||
|
|
||||||
|
|||||||
@ -131,7 +131,7 @@ typedef enum {
|
|||||||
/* 41 */ ST_Group = 0x29,
|
/* 41 */ ST_Group = 0x29,
|
||||||
/* 42 */ ST_Directional = 0x2a, //ae around this target between two angles
|
/* 42 */ ST_Directional = 0x2a, //ae around this target between two angles
|
||||||
/* 43 */ ST_GroupClientAndPet = 0x2b,
|
/* 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,
|
/* 45 */ ST_Ring = 0x2d,
|
||||||
/* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target
|
/* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target
|
||||||
/* 47 */ ST_PetMaster = 0x2f, // uses the master as target
|
/* 47 */ ST_PetMaster = 0x2f, // uses the master as target
|
||||||
|
|||||||
@ -495,6 +495,7 @@ typedef enum {
|
|||||||
GroupSpell, // causes effect to caster + target's group
|
GroupSpell, // causes effect to caster + target's group
|
||||||
CAHateList, // causes effect to all people on caster's hate list within some range
|
CAHateList, // causes effect to all people on caster's hate list within some range
|
||||||
DirectionalAE,
|
DirectionalAE,
|
||||||
|
Beam,
|
||||||
TargetRing,
|
TargetRing,
|
||||||
CastActUnknown
|
CastActUnknown
|
||||||
} CastAction_type;
|
} CastAction_type;
|
||||||
|
|||||||
@ -300,6 +300,8 @@ Mob::Mob(const char* in_name,
|
|||||||
held = false;
|
held = false;
|
||||||
nocast = false;
|
nocast = false;
|
||||||
focused = false;
|
focused = false;
|
||||||
|
_IsTempPet = false;
|
||||||
|
pet_owner_client = false;
|
||||||
|
|
||||||
attacked_count = 0;
|
attacked_count = 0;
|
||||||
mezzed = false;
|
mezzed = false;
|
||||||
|
|||||||
10
zone/mob.h
10
zone/mob.h
@ -235,7 +235,9 @@ public:
|
|||||||
void ResourceTap(int32 damage, uint16 spell_id);
|
void ResourceTap(int32 damage, uint16 spell_id);
|
||||||
void TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker);
|
void TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker);
|
||||||
bool CheckSpellCategory(uint16 spell_id, int category_id, int effect_id);
|
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
|
//Buff
|
||||||
void BuffProcess();
|
void BuffProcess();
|
||||||
@ -674,6 +676,10 @@ public:
|
|||||||
bool HadTempPets() const { return(hasTempPet); }
|
bool HadTempPets() const { return(hasTempPet); }
|
||||||
void TempPets(bool i) { hasTempPet = i; }
|
void TempPets(bool i) { hasTempPet = i; }
|
||||||
bool HasPetAffinity() { if (aabonuses.GivePetGroupTarget || itembonuses.GivePetGroupTarget || spellbonuses.GivePetGroupTarget) return true; return false; }
|
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 GetBodyType() const { return bodytype; }
|
||||||
inline const bodyType GetOrigBodyType() const { return orig_bodytype; }
|
inline const bodyType GetOrigBodyType() const { return orig_bodytype; }
|
||||||
@ -1225,6 +1231,8 @@ protected:
|
|||||||
|
|
||||||
//temppet
|
//temppet
|
||||||
bool hasTempPet;
|
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
|
EGNode *_egnode; //the EG node we are in
|
||||||
float tarx;
|
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());
|
Client *c = entity_list.GetClientByID(GetSwarmOwner());
|
||||||
if(c) {
|
if(c) {
|
||||||
SetAllowBeneficial(1); //Allow client cast swarm pets to be heal/buffed.
|
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'!
|
//This is a hack to allow CLIENT swarm pets NOT to be targeted with F8. Warning: Will turn name 'Yellow'!
|
||||||
if (RuleB(Pets, SwarmPetNotTargetableWithHotKey))
|
if (RuleB(Pets, SwarmPetNotTargetableWithHotKey))
|
||||||
ns->spawn.IsMercenary = 1;
|
ns->spawn.IsMercenary = 1;
|
||||||
@ -1862,16 +1863,20 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
|||||||
ns->spawn.is_pet = 1;
|
ns->spawn.is_pet = 1;
|
||||||
if (!IsCharmed() && GetOwnerID()) {
|
if (!IsCharmed() && GetOwnerID()) {
|
||||||
Client *c = entity_list.GetClientByID(GetOwnerID());
|
Client *c = entity_list.GetClientByID(GetOwnerID());
|
||||||
if(c)
|
if(c){
|
||||||
|
SetPetOwnerClient(true);
|
||||||
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (GetSwarmOwner()) {
|
else if (GetSwarmOwner()) {
|
||||||
ns->spawn.bodytype = 11;
|
ns->spawn.bodytype = 11;
|
||||||
if(!IsCharmed())
|
if(!IsCharmed())
|
||||||
{
|
{
|
||||||
Client *c = entity_list.GetClientByID(GetSwarmOwner());
|
Client *c = entity_list.GetClientByID(GetSwarmOwner());
|
||||||
if(c)
|
if(c){
|
||||||
|
SetPetOwnerClient(true);
|
||||||
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
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;
|
ns->spawn.is_pet = 1;
|
||||||
if (!IsCharmed() && GetOwnerID()) {
|
if (!IsCharmed() && GetOwnerID()) {
|
||||||
Client *c = entity_list.GetClientByID(GetOwnerID());
|
Client *c = entity_list.GetClientByID(GetOwnerID());
|
||||||
if(c)
|
if(c){
|
||||||
|
SetPetOwnerClient(true);
|
||||||
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
ns->spawn.is_pet = 0;
|
ns->spawn.is_pet = 0;
|
||||||
|
|||||||
198
zone/spells.cpp
198
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_Self ||
|
||||||
spell.targettype == ST_AECaster ||
|
spell.targettype == ST_AECaster ||
|
||||||
spell.targettype == ST_Ring ||
|
spell.targettype == ST_Ring ||
|
||||||
|
spell.targettype == ST_Beam ||
|
||||||
spell.targettype == ST_TargetOptional) && target_id == 0)
|
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);
|
mlog(SPELLS__CASTING, "Spell %d auto-targeted the caster. Group? %d, target type %d", spell_id, IsGroupSpell(spell_id), spell.targettype);
|
||||||
@ -1803,6 +1804,14 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ST_Beam:
|
||||||
|
{
|
||||||
|
CastAction = Beam;
|
||||||
|
spell_target = nullptr;
|
||||||
|
ae_center = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ST_Ring:
|
case ST_Ring:
|
||||||
{
|
{
|
||||||
CastAction = TargetRing;
|
CastAction = TargetRing;
|
||||||
@ -2126,54 +2135,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
|||||||
|
|
||||||
case DirectionalAE:
|
case DirectionalAE:
|
||||||
{
|
{
|
||||||
float angle_start = spells[spell_id].directional_start + (GetHeading() * 360.0f / 256.0f);
|
ConeDirectional(spell_id, resist_adjust);
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Beam:
|
||||||
|
{
|
||||||
|
BeamDirectional(spell_id, resist_adjust);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case TargetRing:
|
case TargetRing:
|
||||||
{
|
{
|
||||||
@ -5385,3 +5355,139 @@ void Client::SendSpellAnim(uint16 targetid, uint16 spell_id)
|
|||||||
app.priority = 1;
|
app.priority = 1;
|
||||||
entity_list.QueueCloseClients(this, &app);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user