added some more targetfind stuff to handle pets (needs testing)

This commit is contained in:
Tahir Akhlaq 2017-07-10 23:52:31 +01:00
parent 1637bba167
commit 59fab08230
4 changed files with 172 additions and 34 deletions

View File

@ -104,6 +104,7 @@ namespace FFXIVClassic_Map_Server.Actors
return subpackets; return subpackets;
} }
// todo: handle instance areas in derived class? (see virtuals)
#region Actor Management #region Actor Management
public void AddActorToZone(Actor actor) public void AddActorToZone(Actor actor)
@ -204,12 +205,12 @@ namespace FFXIVClassic_Map_Server.Actors
} }
} }
public List<Actor> GetActorsAroundPoint(float x, float y, int checkDistance) public virtual List<T> GetActorsAroundPoint<T>(float x, float y, int checkDistance) where T : Actor
{ {
checkDistance /= boundingGridSize; checkDistance /= boundingGridSize;
int gridX = (int)x/boundingGridSize; int gridX = (int)x / boundingGridSize;
int gridY = (int)y/boundingGridSize; int gridY = (int)y / boundingGridSize;
gridX += halfWidth; gridX += halfWidth;
gridY += halfHeight; gridY += halfHeight;
@ -224,7 +225,7 @@ namespace FFXIVClassic_Map_Server.Actors
if (gridY >= numYBlocks) if (gridY >= numYBlocks)
gridY = numYBlocks - 1; gridY = numYBlocks - 1;
List<Actor> result = new List<Actor>(); List<T> result = new List<T>();
lock (mActorBlock) lock (mActorBlock)
{ {
@ -232,7 +233,7 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
for (int gy = gridY - checkDistance; gy <= gridY + checkDistance; gy++) for (int gy = gridY - checkDistance; gy <= gridY + checkDistance; gy++)
{ {
result.AddRange(mActorBlock[gx, gy]); result.AddRange(mActorBlock[gx, gy].OfType<T>());
} }
} }
} }
@ -246,11 +247,20 @@ namespace FFXIVClassic_Map_Server.Actors
result.RemoveAt(i); result.RemoveAt(i);
} }
} }
return result; return result;
} }
public List<Actor> GetActorsAroundActor(Actor actor, int checkDistance) public virtual List<Actor> GetActorsAroundPoint(float x, float y, int checkDistance)
{
return GetActorsAroundPoint<Actor>(x, y, checkDistance);
}
public virtual List<Actor> GetActorsAroundActor(Actor actor, int checkDistance)
{
return GetActorsAroundActor<Actor>(actor, checkDistance);
}
public virtual List<T> GetActorsAroundActor<T>(Actor actor, int checkDistance) where T : Actor
{ {
checkDistance /= boundingGridSize; checkDistance /= boundingGridSize;
@ -270,7 +280,7 @@ namespace FFXIVClassic_Map_Server.Actors
if (gridY >= numYBlocks) if (gridY >= numYBlocks)
gridY = numYBlocks - 1; gridY = numYBlocks - 1;
List<Actor> result = new List<Actor>(); var result = new List<T>();
lock (mActorBlock) lock (mActorBlock)
{ {
@ -278,10 +288,11 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
for (int gx = ((gridX - checkDistance) < 0 ? 0 : (gridX - checkDistance)); gx <= ((gridX + checkDistance) >= numXBlocks ? numXBlocks - 1 : (gridX + checkDistance)); gx++) for (int gx = ((gridX - checkDistance) < 0 ? 0 : (gridX - checkDistance)); gx <= ((gridX + checkDistance) >= numXBlocks ? numXBlocks - 1 : (gridX + checkDistance)); gx++)
{ {
result.AddRange(mActorBlock[gx, gy]); result.AddRange(mActorBlock[gx, gy].OfType<T>());
} }
} }
} }
//Remove players if isolation zone //Remove players if isolation zone
if (isIsolated) if (isIsolated)
{ {
@ -327,13 +338,10 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
lock (mActorList) lock (mActorList)
{ {
foreach (Actor a in mActorList.Values) foreach (Player player in mActorList.Values.OfType<Player>())
{ {
if (a is Player) if (player.customDisplayName.ToLower().Equals(name.ToLower()))
{ return player;
if (((Player)a).customDisplayName.ToLower().Equals(name.ToLower()))
return (Player)a;
}
} }
return null; return null;
} }
@ -369,19 +377,22 @@ namespace FFXIVClassic_Map_Server.Actors
} }
// todo: for zones override this to seach contentareas (assuming flag is passed) // todo: for zones override this to seach contentareas (assuming flag is passed)
public virtual List<Actor> GetAllActors() public virtual List<T> GetAllActors<T>() where T : Actor
{ {
lock (mActorList) lock (mActorList)
{ {
List<Actor> actorList = new List<Actor>(mActorList.Count); List<T> actorList = new List<T>(mActorList.Count);
foreach (var actor in mActorList.Values) actorList.AddRange(mActorList.Values.OfType<T>());
{
actorList.Add(actor);
}
return actorList; return actorList;
} }
} }
public virtual List<Actor> GetAllActors()
{
return GetAllActors<Actor>();
}
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)

View File

@ -88,6 +88,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
this.controller = controller; this.controller = controller;
} }
public Controller GetController()
{
return controller;
}
public bool CanChangeState() public bool CanChangeState()
{ {
return states.Count == 0 || states.Peek().CanInterrupt(); return states.Count == 0 || states.Peek().CanInterrupt();

View File

@ -5,6 +5,8 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.chara.ai;
using FFXIVClassic_Map_Server.actors.chara.ai.controllers;
// port of dsp's ai code https://github.com/DarkstarProject/darkstar/blob/master/src/map/ai/ // port of dsp's ai code https://github.com/DarkstarProject/darkstar/blob/master/src/map/ai/
@ -67,6 +69,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{ {
private Character owner; private Character owner;
private Character target; private Character target;
private Character masterTarget; // if target is a pet, this is the owner
private TargetFindCharacterType findType; private TargetFindCharacterType findType;
private TargetFindFlags findFlags; private TargetFindFlags findFlags;
private TargetFindAOEType aoeType; private TargetFindAOEType aoeType;
@ -128,19 +131,48 @@ 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>
/// <param name="withPet">Include pets?</param>
public void FindWithinArea(Character target, TargetFindFlags flags, bool withPet) public void FindWithinArea(Character target, TargetFindFlags flags)
{ {
// todo: maybe we should keep a snapshot which is only updated on each tick for consistency findFlags = flags;
// 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)
this.targetPosition = owner.GetPosAsVector3(); this.targetPosition = owner.GetPosAsVector3();
else else
this.targetPosition = new Vector3(target.positionX, target.positionY, target.positionZ); this.targetPosition = target.GetPosAsVector3();
this.findFlags = flags; masterTarget = GetMasterTarget(target);
// todo: this is stupid
bool withPet = (flags & TargetFindFlags.Pets) != 0 || masterTarget.currentSubState != owner.currentSubState;
if (IsPlayer(owner))
{
if (masterTarget is Player)
{
findType = TargetFindCharacterType.PlayerToPlayer;
// todo: handle player parties
if (masterTarget.currentParty != null)
{
if ((findFlags & TargetFindFlags.Alliance) != 0)
AddAllInAlliance(masterTarget, withPet);
else
AddAllInParty(masterTarget, withPet);
}
else
{
AddTarget(masterTarget, withPet);
}
}
else
{
findType = TargetFindCharacterType.PlayerToBattleNpc;
}
}
if (aoeType == TargetFindAOEType.Box) if (aoeType == TargetFindAOEType.Box)
{ {
FindWithinBox(withPet); FindWithinBox(withPet);
@ -149,6 +181,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{ {
FindWithinCircle(withPet); FindWithinCircle(withPet);
} }
else if (aoeType == TargetFindAOEType.Cone)
{
FindWithinCone(withPet);
}
} }
/// <summary> /// <summary>
@ -163,7 +199,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
// if we have flag set to hit all characters in zone, do it // if we have flag set to hit all characters in zone, do it
// todo: make the distance check modifiable // todo: make the distance check modifiable
var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors() : owner.zone.GetActorsAroundActor(owner, 30); var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors<Character>() : owner.zone.GetActorsAroundActor<Character>(owner, 70);
var myPos = owner.GetPosAsVector3(); var myPos = owner.GetPosAsVector3();
var angle = Vector3.GetAngle(myPos, targetPosition); var angle = Vector3.GetAngle(myPos, targetPosition);
@ -174,12 +210,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
var targetCorner = targetPosition.NewHorizontalVector(angle, extents); var targetCorner = targetPosition.NewHorizontalVector(angle, extents);
var targetCorner2 = targetPosition.NewHorizontalVector(angle, -extents); var targetCorner2 = targetPosition.NewHorizontalVector(angle, -extents);
foreach (Character actor in actors) foreach (Character actor in actors.OfType<Character>())
{ {
// dont wanna add static actors // dont wanna add static actors
if (actor is Player || actor is BattleNpc) if (actor is Player || actor is BattleNpc)
{ {
if (actor.GetPosAsVector3().IsWithinBox(myCorner2, targetCorner)) if (actor.GetPosAsVector3().IsWithinBox(targetCorner2, myCorner))
{ {
if (CanTarget(actor)) if (CanTarget(actor))
AddTarget(actor, withPet); AddTarget(actor, withPet);
@ -196,18 +232,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
/// </summary> /// </summary>
private void FindWithinCircle(bool withPet) private void FindWithinCircle(bool withPet)
{ {
var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors() : owner.zone.GetActorsAroundActor(owner, 30); var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors<Character>() : owner.zone.GetActorsAroundActor<Character>(owner, 70);
foreach (Character target in actors) foreach (Character actor in actors)
{ {
if (target is Player || target is BattleNpc) if (actor is Player || actor is BattleNpc)
{ {
if (target.GetPosAsVector3().IsWithinCircle(targetPosition, extents)) if (actor.GetPosAsVector3().IsWithinCircle(targetPosition, extents))
AddTarget(target, withPet); AddTarget(target, withPet);
} }
} }
} }
private void FindWithinCone(bool withPet)
{
}
private void AddTarget(Character target, bool withPet) private void AddTarget(Character target, bool withPet)
{ {
if (CanTarget(target)) if (CanTarget(target))
@ -220,11 +261,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private void AddAllInParty(Character target, bool withPet) private void AddAllInParty(Character target, bool withPet)
{ {
// todo: // todo:
AddTarget(target, withPet);
} }
private void AddAllInAlliance(Character target, bool withPet) private void AddAllInAlliance(Character target, bool withPet)
{ {
// todo: // todo:
AddTarget(target, withPet);
} }
public bool CanTarget(Character target) public bool CanTarget(Character target)
@ -241,8 +284,32 @@ 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;
} }
private bool IsPlayer(Character target)
{
if (target is Player)
return true;
// treat player owned pets as players too
return GetMasterTarget(target) is Player;
}
private Character GetMasterTarget(Character target)
{
// if character is a player owned pet, treat as a player
if (target.aiContainer != null)
{
var controller = target.aiContainer.GetController();
if (controller != null && controller is PetController)
{
return ((PetController)controller).GetPetMaster();
}
}
return target;
}
} }
} }

View File

@ -3,10 +3,65 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors;
namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers
{ {
class PetController class PetController : Controller
{ {
private Character petMaster;
public PetController(Character owner)
{
this.owner = owner;
this.lastUpdate = Program.Tick;
}
public override void Update(DateTime tick)
{
// todo: handle player stuff on tick
}
public override void ChangeTarget(Character target)
{
base.ChangeTarget(target);
}
public override bool Engage(Character target)
{
// todo: check distance, last swing time, status effects
return true;
}
public override bool Disengage()
{
// todo:
return true;
}
public override void Cast(Character target, uint spellId)
{
}
public override void Ability(Character target, uint abilityId)
{
}
public override void RangedAttack(Character target)
{
}
public Character GetPetMaster()
{
return petMaster;
}
public void SetPetMaster(Character master)
{
petMaster = master;
}
} }
} }