1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-23 21:27:46 +00:00

cleaned targetfind some

- added character allegiance types
This commit is contained in:
Tahir Akhlaq 2017-07-11 01:54:15 +01:00
parent 59fab08230
commit 84d5eee1fc
6 changed files with 149 additions and 76 deletions

View file

@ -10,7 +10,16 @@ using System;
namespace FFXIVClassic_Map_Server.Actors namespace FFXIVClassic_Map_Server.Actors
{ {
class Character:Actor /// <summary> Which Character types am I friendly with </summary>
enum CharacterTargetingAllegiance
{
/// <summary> Friendly to Players </summary>
Player,
/// <summary> Friendly to BattleNpcs </summary>
BattleNpcs
}
class Character : Actor
{ {
public const int SIZE = 0; public const int SIZE = 0;
public const int COLORINFO = 1; public const int COLORINFO = 1;
@ -66,6 +75,8 @@ namespace FFXIVClassic_Map_Server.Actors
public AIContainer aiContainer; public AIContainer aiContainer;
public StatusEffects statusEffects; public StatusEffects statusEffects;
public CharacterTargetingAllegiance allegiance;
public Character(uint actorID) : base(actorID) public Character(uint actorID) : base(actorID)
{ {
//Init timer array to "notimer" //Init timer array to "notimer"

View file

@ -18,7 +18,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{ {
None, None,
/// <summary> Able to target <see cref="Player"/>s even if not in target's party </summary> /// <summary> Able to target <see cref="Player"/>s even if not in target's party </summary>
All, HitAll,
/// <summary> Able to target all <see cref="Player"/>s in target's party/alliance </summary> /// <summary> Able to target all <see cref="Player"/>s in target's party/alliance </summary>
Alliance, Alliance,
/// <summary> Able to target any <see cref="Pet"/> in target's party/alliance </summary> /// <summary> Able to target any <see cref="Pet"/> in target's party/alliance </summary>
@ -98,6 +98,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
this.targets = new List<Character>(); this.targets = new List<Character>();
} }
public List<T> GetTargets<T>() where T : Character
{
return new List<T>(targets.OfType<T>());
}
public List<Character> GetTargets()
{
return targets;
}
/// <summary> /// <summary>
/// Call this before <see cref="FindWithinArea"/> <para/> /// Call this before <see cref="FindWithinArea"/> <para/>
/// </summary> /// </summary>
@ -131,11 +141,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
/// <para> Call SetAOEType before calling this </para> /// <para> Call SetAOEType before calling this </para>
/// Find targets within area set by <see cref="SetAOEType"/> /// Find targets within area set by <see cref="SetAOEType"/>
/// </summary> /// </summary>
public void FindWithinArea(Character target, TargetFindFlags flags) public void FindWithinArea(Character target, TargetFindFlags flags)
{ {
findFlags = flags; findFlags = flags;
// todo: maybe we should keep a snapshot which is only updated on each tick for consistency // 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 // are we creating aoe circles around target or self
if ((aoeType & TargetFindAOEType.Circle) != 0 && radiusType != TargetFindAOERadiusType.Self) if ((aoeType & TargetFindAOEType.Circle) != 0 && radiusType != TargetFindAOERadiusType.Self)
@ -143,10 +151,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
else else
this.targetPosition = target.GetPosAsVector3(); this.targetPosition = target.GetPosAsVector3();
masterTarget = GetMasterTarget(target); masterTarget = TryGetMasterTarget(target) ?? target;
// todo: should i set this yet or wait til checked if valid target
this.target = target;
// todo: this is stupid // todo: this is stupid
bool withPet = (flags & TargetFindFlags.Pets) != 0 || masterTarget.currentSubState != owner.currentSubState; bool withPet = (flags & TargetFindFlags.Pets) != 0 || masterTarget.allegiance != owner.allegiance;
if (IsPlayer(owner)) if (IsPlayer(owner))
{ {
@ -170,83 +181,63 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
else else
{ {
findType = TargetFindCharacterType.PlayerToBattleNpc; findType = TargetFindCharacterType.PlayerToBattleNpc;
AddAllBattleNpcs(masterTarget, false);
} }
} }
if (aoeType == TargetFindAOEType.Box) else
{ {
FindWithinBox(withPet); // todo: this needs checking..
} if (masterTarget is Player || owner.allegiance == CharacterTargetingAllegiance.Player)
else if (aoeType == TargetFindAOEType.Circle) findType = TargetFindCharacterType.BattleNpcToPlayer;
{ else
FindWithinCircle(withPet); findType = TargetFindCharacterType.BattleNpcToBattleNpc;
}
else if (aoeType == TargetFindAOEType.Cone) // todo: configurable pet aoe buff
{ if (findType == TargetFindCharacterType.BattleNpcToBattleNpc && TryGetMasterTarget(target) != null)
FindWithinCone(withPet); withPet = true;
// todo: does ffxiv have call for help flag?
//if ((findFlags & TargetFindFlags.HitAll) != 0)
//{
// AddAllInZone(masterTarget, withPet);
//}
AddAllInAlliance(target, withPet);
if (findType == TargetFindCharacterType.BattleNpcToPlayer)
{
if (owner.allegiance == CharacterTargetingAllegiance.Player)
AddAllInZone(masterTarget, withPet);
else
AddAllInHateList();
}
} }
} }
/// <summary> /// <summary>
/// Find targets within a box using owner's coordinates and target's coordinates as length /// 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 /// with corners being `extents` yalms to either side of self and target
/// </summary> /// </summary>
private void FindWithinBox(bool withPet) private bool IsWithinBox(Character target, bool withPet)
{ {
// todo: loop over party members var myPos = owner.GetPosAsVector3();
if ((findFlags & TargetFindFlags.All) != 0) var angle = Vector3.GetAngle(myPos, targetPosition);
{
// if we have flag set to hit all characters in zone, do it
// todo: make the distance check modifiable // todo: actually check this works..
var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors<Character>() : owner.zone.GetActorsAroundActor<Character>(owner, 70); var myCorner = myPos.NewHorizontalVector(angle, extents);
var myPos = owner.GetPosAsVector3(); var myCorner2 = myPos.NewHorizontalVector(angle, -extents);
var angle = Vector3.GetAngle(myPos, targetPosition);
// todo: actually check this works.. var targetCorner = targetPosition.NewHorizontalVector(angle, extents);
var myCorner = myPos.NewHorizontalVector(angle, extents); var targetCorner2 = targetPosition.NewHorizontalVector(angle, -extents);
var myCorner2 = myPos.NewHorizontalVector(angle, -extents);
var targetCorner = targetPosition.NewHorizontalVector(angle, extents); return target.GetPosAsVector3().IsWithinBox(targetCorner2, myCorner);
var targetCorner2 = targetPosition.NewHorizontalVector(angle, -extents);
foreach (Character actor in actors.OfType<Character>())
{
// dont wanna add static actors
if (actor is Player || actor is BattleNpc)
{
if (actor.GetPosAsVector3().IsWithinBox(targetCorner2, myCorner))
{
if (CanTarget(actor))
AddTarget(actor, withPet);
}
}
}
}
} }
/// <summary> private bool IsWithinCone(Character target, bool withPet)
/// 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<Character>() : owner.zone.GetActorsAroundActor<Character>(owner, 70); // todo:
return false;
foreach (Character actor in actors)
{
if (actor is Player || actor is BattleNpc)
{
if (actor.GetPosAsVector3().IsWithinCircle(targetPosition, extents))
AddTarget(target, withPet);
}
}
}
private void FindWithinCone(bool withPet)
{
} }
private void AddTarget(Character target, bool withPet) private void AddTarget(Character target, bool withPet)
@ -261,16 +252,61 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private void AddAllInParty(Character target, bool withPet) private void AddAllInParty(Character target, bool withPet)
{ {
// todo: // todo:
/*
* foreach (var actor in target.currentParty.GetMembers())
* {
* AddTarget(actor, withPet);
* }
*/
AddTarget(target, withPet); AddTarget(target, withPet);
} }
private void AddAllInAlliance(Character target, bool withPet) private void AddAllInAlliance(Character target, bool withPet)
{ {
// todo: // todo:
/*
* foreach (var actor in target.currentParty.GetAllianceMembers())
* {
* AddTarget(actor, withPet);
* }
*/
AddTarget(target, withPet); AddTarget(target, withPet);
} }
public bool CanTarget(Character target) private void AddAllBattleNpcs(Character target, bool withPet)
{
// 70 is client render distance so we'll go with that
var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors<BattleNpc>() : owner.zone.GetActorsAroundActor<BattleNpc>(owner, 70);
// todo: should we look for Characters instead in case player is charmed by BattleNpc
foreach (BattleNpc actor in actors)
{
// todo:
AddTarget(actor, false);
}
}
private void AddAllInZone(Character target, bool withPet)
{
var actors = owner.zone.GetAllActors<Character>();
foreach (Character actor in actors)
{
AddTarget(actor, withPet);
}
}
private void AddAllInHateList()
{
if (!(owner is BattleNpc))
Program.Log.Error($"TargetFind.AddAllInHateList() owner [{owner.actorId}] {owner.customDisplayName} {owner.actorName} is not a BattleNpc");
foreach (var hateEntry in ((BattleNpc)owner).hateContainer.GetHateList())
{
AddTarget(hateEntry.Value.actor, false);
}
}
public bool CanTarget(Character target, bool withPet = false)
{ {
// already targeted, dont target again // already targeted, dont target again
if (targets.Contains(target)) if (targets.Contains(target))
@ -280,13 +316,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
if ((findFlags & TargetFindFlags.Dead) == 0 && target.IsDead()) if ((findFlags & TargetFindFlags.Dead) == 0 && target.IsDead())
return false; return false;
// cant target if player is zoning bool targetingPlayer = target is Player;
if (target is Player && ((Player)target).playerSession.isUpdatesLocked)
// cant target if zoning
if (target.isZoning || owner.isZoning || target.zone != owner.zone || targetingPlayer && ((Player)target).playerSession.isUpdatesLocked)
return false; return false;
// hit everything within zone or within aoe region
if ((findFlags & TargetFindFlags.ZoneWide) != 0 || aoeType == TargetFindAOEType.Circle && target.GetPosAsVector3().IsWithinCircle(targetPosition, extents))
return true;
if (aoeType == TargetFindAOEType.Cone && IsWithinCone(target, withPet))
return true;
return true; if (aoeType == TargetFindAOEType.Box && IsWithinBox(target, withPet))
return true;
return false;
} }
private bool IsPlayer(Character target) private bool IsPlayer(Character target)
@ -295,21 +341,30 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
return true; return true;
// treat player owned pets as players too // treat player owned pets as players too
return GetMasterTarget(target) is Player; return TryGetMasterTarget(target) is Player;
} }
private Character GetMasterTarget(Character target) private Character TryGetMasterTarget(Character target)
{ {
// if character is a player owned pet, treat as a player // if character is a player owned pet, treat as a player
if (target.aiContainer != null) if (target.aiContainer != null)
{ {
var controller = target.aiContainer.GetController(); var controller = target.aiContainer.GetController();
if (controller != null && controller is PetController) if (controller != null && controller is PetController)
{
return ((PetController)controller).GetPetMaster(); return ((PetController)controller).GetPetMaster();
}
} }
return target; return null;
}
private bool IsBattleNpcOwner(Character target)
{
// i know i copied this from dsp but what even
if (!(owner is Player) || target is Player)
return true;
// todo: check hate list
return false;
} }
} }
} }

View file

@ -62,6 +62,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
public void SetPetMaster(Character master) public void SetPetMaster(Character master)
{ {
petMaster = master; petMaster = master;
if (master is Player)
owner.allegiance = CharacterTargetingAllegiance.Player;
else
owner.allegiance = CharacterTargetingAllegiance.BattleNpcs;
} }
} }
} }

View file

@ -24,6 +24,7 @@ namespace FFXIVClassic_Map_Server.Actors
this.aiContainer = new AIContainer(this, new BattleNpcController(this), new PathFind(this), new TargetFind(this)); this.aiContainer = new AIContainer(this, new BattleNpcController(this), new PathFind(this), new TargetFind(this));
this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER; this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER;
this.hateContainer = new HateContainer(this); this.hateContainer = new HateContainer(this);
this.allegiance = CharacterTargetingAllegiance.BattleNpcs;
} }
} }
} }

View file

@ -17,7 +17,7 @@ namespace FFXIVClassic_Map_Server.Actors
ushort actorState, uint animationId, string customDisplayName) ushort actorState, uint animationId, string customDisplayName)
: base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName) : base(actorNumber, actorClass, uniqueId, spawnedArea, posX, posY, posZ, rot, actorState, animationId, customDisplayName)
{ {
this.aiContainer = new AIContainer(this, new BattleNpcController(this), new PathFind(this), new TargetFind(this)); this.aiContainer = new AIContainer(this, new PetController(this), new PathFind(this), new TargetFind(this));
this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER; this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER;
this.hateContainer = new HateContainer(this); this.hateContainer = new HateContainer(this);
} }

View file

@ -251,6 +251,7 @@ namespace FFXIVClassic_Map_Server.Actors
lastPlayTimeUpdate = Utils.UnixTimeStampUTC(); lastPlayTimeUpdate = Utils.UnixTimeStampUTC();
this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this)); this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this));
allegiance = CharacterTargetingAllegiance.Player;
} }
public List<SubPacket> Create0x132Packets() public List<SubPacket> Create0x132Packets()