mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-02 19:42:05 -04:00
added target finding within box (thanks kjLotus!)
- added function to return position as Vector3 to Actor (todo: maybe we should just use the class instead of 3 separate floats?) - added function to return all actors in Area - actually added documentation to TargetFind stuff (kill me pls) - todo: actually test this..
This commit is contained in:
parent
4ed8f3e5e2
commit
1637bba167
@ -70,5 +70,41 @@ namespace FFXIVClassic.Common
|
|||||||
{
|
{
|
||||||
return (lhs.X * rhs.X) + (lhs.Y * rhs.Y) + (lhs.Z * rhs.Z);
|
return (lhs.X * rhs.X) + (lhs.Y * rhs.Y) + (lhs.Z * rhs.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float GetAngle(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
var angle = (float)Math.Atan((rhs.Z - lhs.Z) / (rhs.X - lhs.X));
|
||||||
|
return lhs.X > rhs.X ? angle + (float)Math.PI : angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 NewHorizontalVector(float angle, float extents)
|
||||||
|
{
|
||||||
|
var newVec = new Vector3();
|
||||||
|
newVec.Y = this.Y;
|
||||||
|
newVec.X = this.X + (float)Math.Cos(angle) * extents;
|
||||||
|
newVec.Z = this.Z + (float)Math.Sin(angle) * extents;
|
||||||
|
|
||||||
|
return newVec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsWithinCircle(Vector3 centre, float radius)
|
||||||
|
{
|
||||||
|
float diffX = centre.X - this.X;
|
||||||
|
float diffZ = centre.Z - this.Z;
|
||||||
|
|
||||||
|
float distance = (float)Math.Sqrt((diffX * diffX) + (diffZ * diffZ));
|
||||||
|
|
||||||
|
return distance < radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsWithinBox(Vector3 upperLeftCorner, Vector3 lowerRightCorner)
|
||||||
|
{
|
||||||
|
return upperLeftCorner.X <= this.X &&
|
||||||
|
upperLeftCorner.Y <= this.Y &&
|
||||||
|
upperLeftCorner.Z <= this.Z &&
|
||||||
|
lowerRightCorner.X >= this.X &&
|
||||||
|
lowerRightCorner.Y >= this.Y &&
|
||||||
|
lowerRightCorner.Z >= this.Z;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -544,6 +544,11 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector3 GetPosAsVector3()
|
||||||
|
{
|
||||||
|
return new Vector3(positionX, positionY, positionZ);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetPos(float x, float y, float z, float rot = 0, uint zoneId = 0)
|
public void SetPos(float x, float y, float z, float rot = 0, uint zoneId = 0)
|
||||||
{
|
{
|
||||||
oldPositionX = positionX;
|
oldPositionX = positionX;
|
||||||
|
@ -368,6 +368,20 @@ namespace FFXIVClassic_Map_Server.Actors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: for zones override this to seach contentareas (assuming flag is passed)
|
||||||
|
public virtual List<Actor> GetAllActors()
|
||||||
|
{
|
||||||
|
lock (mActorList)
|
||||||
|
{
|
||||||
|
List<Actor> actorList = new List<Actor>(mActorList.Count);
|
||||||
|
foreach (var actor in mActorList.Values)
|
||||||
|
{
|
||||||
|
actorList.Add(actor);
|
||||||
|
}
|
||||||
|
return actorList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void BroadcastPacketsAroundActor(Actor actor, List<SubPacket> packets)
|
public void BroadcastPacketsAroundActor(Actor actor, List<SubPacket> packets)
|
||||||
{
|
{
|
||||||
foreach (SubPacket packet in packets)
|
foreach (SubPacket packet in packets)
|
||||||
|
@ -10,40 +10,59 @@ using FFXIVClassic.Common;
|
|||||||
|
|
||||||
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
namespace FFXIVClassic_Map_Server.actors.chara.ai
|
||||||
{
|
{
|
||||||
|
/// <summary> todo: what even do i summarise this as? </summary>
|
||||||
[Flags]
|
[Flags]
|
||||||
enum TargetFindFlags : ushort
|
enum TargetFindFlags
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
All, // able to target players who arent in party
|
/// <summary> Able to target <see cref="Player"/>s even if not in target's party </summary>
|
||||||
Alliance, // alliance
|
All,
|
||||||
Pet, // allow targeting pets
|
/// <summary> Able to target all <see cref="Player"/>s in target's party/alliance </summary>
|
||||||
ZoneWide, //
|
Alliance,
|
||||||
Dead, // allow targeting of dead players
|
/// <summary> Able to target any <see cref="Pet"/> in target's party/alliance </summary>
|
||||||
|
Pets,
|
||||||
|
/// <summary> Target all in zone, regardless of distance </summary>
|
||||||
|
ZoneWide,
|
||||||
|
/// <summary> Able to target dead <see cref="Player"/>s </summary>
|
||||||
|
Dead,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Targeting from/to different entity types </summary>
|
||||||
enum TargetFindCharacterType
|
enum TargetFindCharacterType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
PlayerToPlayer, // player can target all players in party
|
/// <summary> Player can target all <see cref="Player">s in party </summary>
|
||||||
PlayerToBattleNpc, // player can target all battlenpc (excluding player owned pets)
|
PlayerToPlayer,
|
||||||
BattleNpcToBattleNpc, // battlenpc can target other battlenpcs
|
/// <summary> Player can target all <see cref="BattleNpc"/>s (excluding player owned <see cref="Pet"/>s) </summary>
|
||||||
BattleNpcToPlayer, // battlenpc can target players
|
PlayerToBattleNpc,
|
||||||
|
/// <summary> BattleNpc can target other <see cref="BattleNpc"/>s </summary>
|
||||||
|
BattleNpcToBattleNpc,
|
||||||
|
/// <summary> BattleNpc can target <see cref="Player"/>s and their <see cref="Pet"/>s </summary>
|
||||||
|
BattleNpcToPlayer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Type of AOE region to create </summary>
|
||||||
enum TargetFindAOEType
|
enum TargetFindAOEType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
/// <summary> Really a cylinder, uses extents parameter in SetAOEType </summary>
|
||||||
Circle,
|
Circle,
|
||||||
|
/// <summary> Create a cone with angle in radians </summary>
|
||||||
Cone,
|
Cone,
|
||||||
|
/// <summary> Box using self/target coords and </summary>
|
||||||
Box
|
Box
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Set AOE around self or target </summary>
|
||||||
enum TargetFindAOERadiusType
|
enum TargetFindAOERadiusType
|
||||||
{
|
{
|
||||||
|
/// <summary> Set AOE's origin at target's position </summary>
|
||||||
Target,
|
Target,
|
||||||
|
/// <summary> Set AOE's origin to own position. </summary>
|
||||||
Self
|
Self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Target finding helper class </summary>
|
||||||
class TargetFind
|
class TargetFind
|
||||||
{
|
{
|
||||||
private Character owner;
|
private Character owner;
|
||||||
@ -51,8 +70,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
private TargetFindCharacterType findType;
|
private TargetFindCharacterType findType;
|
||||||
private TargetFindFlags findFlags;
|
private TargetFindFlags findFlags;
|
||||||
private TargetFindAOEType aoeType;
|
private TargetFindAOEType aoeType;
|
||||||
|
private TargetFindAOERadiusType radiusType;
|
||||||
private Vector3 targetPosition;
|
private Vector3 targetPosition;
|
||||||
private float range;
|
private float extents;
|
||||||
private float angle;
|
private float angle;
|
||||||
private List<Character> targets;
|
private List<Character> targets;
|
||||||
|
|
||||||
@ -67,48 +87,144 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
this.target = null;
|
this.target = null;
|
||||||
this.findType = TargetFindCharacterType.None;
|
this.findType = TargetFindCharacterType.None;
|
||||||
this.findFlags = TargetFindFlags.None;
|
this.findFlags = TargetFindFlags.None;
|
||||||
|
this.aoeType = TargetFindAOEType.None;
|
||||||
|
this.radiusType = TargetFindAOERadiusType.Self;
|
||||||
this.targetPosition = null;
|
this.targetPosition = null;
|
||||||
this.range = 0.0f;
|
this.extents = 0.0f;
|
||||||
this.angle = 0.0f;
|
this.angle = 0.0f;
|
||||||
|
this.targets = new List<Character>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAOEType(TargetFindAOEType type, float range = -1.0f, float angle = -1.0f)
|
/// <summary>
|
||||||
|
/// Call this before <see cref="FindWithinArea"/> <para/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="extents">
|
||||||
|
/// <see cref="TargetFindAOEType.Circle"/> - radius of circle <para/>
|
||||||
|
/// <see cref="TargetFindAOEType.Cone"/> - height of cone <para/>
|
||||||
|
/// <see cref="TargetFindAOEType.Box"/> - width of box / 2
|
||||||
|
/// </param>
|
||||||
|
/// <param name="angle"> Angle in radians of cone </param>
|
||||||
|
public void SetAOEType(TargetFindAOERadiusType radiusType, TargetFindAOEType aoeType, float extents = -1.0f, float angle = -1.0f)
|
||||||
{
|
{
|
||||||
aoeType = type;
|
this.radiusType = TargetFindAOERadiusType.Target;
|
||||||
range = range != -1.0f ? range : 0.0f;
|
this.aoeType = aoeType;
|
||||||
angle = angle != -1.0f ? angle : 0.0f;
|
this.extents = extents != -1.0f ? extents : 0.0f;
|
||||||
|
this.angle = angle != -1.0f ? angle : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find and try to add a single target to target list
|
||||||
|
/// </summary>
|
||||||
public void FindTarget(Character target, TargetFindFlags flags)
|
public void FindTarget(Character target, TargetFindFlags flags)
|
||||||
{
|
{
|
||||||
findFlags = flags;
|
findFlags = flags;
|
||||||
this.target = null;
|
this.target = null;
|
||||||
this.targetPosition = new Vector3(target.positionX, target.positionY, target.positionZ);
|
// todo: maybe this should only be set if successfully added?
|
||||||
|
this.targetPosition = target.GetPosAsVector3();
|
||||||
AddTarget(target, false);
|
AddTarget(target, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FindWithinArea(Character target, float radius, TargetFindFlags flags)
|
/// <summary>
|
||||||
{
|
/// <para> Call SetAOEType before calling this </para>
|
||||||
|
/// Find targets within area set by <see cref="SetAOEType"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="withPet">Include pets?</param>
|
||||||
|
|
||||||
|
public void FindWithinArea(Character target, TargetFindFlags flags, bool withPet)
|
||||||
|
{
|
||||||
|
// todo: maybe we should keep a snapshot which is only updated on each tick for consistency
|
||||||
|
|
||||||
|
// are we creating aoe circles around target or self
|
||||||
|
if ((aoeType & TargetFindAOEType.Circle) != 0 && radiusType != TargetFindAOERadiusType.Self)
|
||||||
|
this.targetPosition = owner.GetPosAsVector3();
|
||||||
|
else
|
||||||
|
this.targetPosition = new Vector3(target.positionX, target.positionY, target.positionZ);
|
||||||
|
|
||||||
|
this.findFlags = flags;
|
||||||
|
if (aoeType == TargetFindAOEType.Box)
|
||||||
|
{
|
||||||
|
FindWithinBox(withPet);
|
||||||
|
}
|
||||||
|
else if (aoeType == TargetFindAOEType.Circle)
|
||||||
|
{
|
||||||
|
FindWithinCircle(withPet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find targets within a box using owner's coordinates and target's coordinates as length
|
||||||
|
/// with corners being `extents` yalms to either side of self and target
|
||||||
|
/// </summary>
|
||||||
|
private void FindWithinBox(bool withPet)
|
||||||
|
{
|
||||||
|
// todo: loop over party members
|
||||||
|
if ((findFlags & TargetFindFlags.All) != 0)
|
||||||
|
{
|
||||||
|
// if we have flag set to hit all characters in zone, do it
|
||||||
|
|
||||||
|
// todo: make the distance check modifiable
|
||||||
|
var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors() : owner.zone.GetActorsAroundActor(owner, 30);
|
||||||
|
var myPos = owner.GetPosAsVector3();
|
||||||
|
var angle = Vector3.GetAngle(myPos, targetPosition);
|
||||||
|
|
||||||
|
// todo: actually check this works..
|
||||||
|
var myCorner = myPos.NewHorizontalVector(angle, extents);
|
||||||
|
var myCorner2 = myPos.NewHorizontalVector(angle, -extents);
|
||||||
|
|
||||||
|
var targetCorner = targetPosition.NewHorizontalVector(angle, extents);
|
||||||
|
var targetCorner2 = targetPosition.NewHorizontalVector(angle, -extents);
|
||||||
|
|
||||||
|
foreach (Character actor in actors)
|
||||||
|
{
|
||||||
|
// dont wanna add static actors
|
||||||
|
if (actor is Player || actor is BattleNpc)
|
||||||
|
{
|
||||||
|
if (actor.GetPosAsVector3().IsWithinBox(myCorner2, targetCorner))
|
||||||
|
{
|
||||||
|
if (CanTarget(actor))
|
||||||
|
AddTarget(actor, withPet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find targets within circle area. <para/>
|
||||||
|
/// As the name implies, it only checks horizontal coords, not vertical -
|
||||||
|
/// effectively creating cylinder with infinite height
|
||||||
|
/// </summary>
|
||||||
|
private void FindWithinCircle(bool withPet)
|
||||||
|
{
|
||||||
|
var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors() : owner.zone.GetActorsAroundActor(owner, 30);
|
||||||
|
|
||||||
|
foreach (Character target in actors)
|
||||||
|
{
|
||||||
|
if (target is Player || target is BattleNpc)
|
||||||
|
{
|
||||||
|
if (target.GetPosAsVector3().IsWithinCircle(targetPosition, extents))
|
||||||
|
AddTarget(target, withPet);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddTarget(Character target, bool withPet)
|
private void AddTarget(Character target, bool withPet)
|
||||||
{
|
{
|
||||||
if (CanTarget(target))
|
if (CanTarget(target))
|
||||||
|
{
|
||||||
|
// todo: add pets too
|
||||||
targets.Add(target);
|
targets.Add(target);
|
||||||
|
}
|
||||||
// todo: add pets too
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAllInParty(Character target, bool withPet)
|
private void AddAllInParty(Character target, bool withPet)
|
||||||
{
|
{
|
||||||
|
// todo:
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAllInAlliance(Character target, bool withPet)
|
private void AddAllInAlliance(Character target, bool withPet)
|
||||||
{
|
{
|
||||||
|
// todo:
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanTarget(Character target)
|
public bool CanTarget(Character target)
|
||||||
@ -125,9 +241,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
|
|||||||
if (target is Player && ((Player)target).playerSession.isUpdatesLocked)
|
if (target is Player && ((Player)target).playerSession.isUpdatesLocked)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user