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;
}
// todo: handle instance areas in derived class? (see virtuals)
#region Actor Management
public void AddActorToZone(Actor actor)
@ -204,7 +205,7 @@ 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;
@ -224,7 +225,7 @@ namespace FFXIVClassic_Map_Server.Actors
if (gridY >= numYBlocks)
gridY = numYBlocks - 1;
List<Actor> result = new List<Actor>();
List<T> result = new List<T>();
lock (mActorBlock)
{
@ -232,7 +233,7 @@ namespace FFXIVClassic_Map_Server.Actors
{
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);
}
}
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;
@ -270,7 +280,7 @@ namespace FFXIVClassic_Map_Server.Actors
if (gridY >= numYBlocks)
gridY = numYBlocks - 1;
List<Actor> result = new List<Actor>();
var result = new List<T>();
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++)
{
result.AddRange(mActorBlock[gx, gy]);
result.AddRange(mActorBlock[gx, gy].OfType<T>());
}
}
}
//Remove players if isolation zone
if (isIsolated)
{
@ -327,13 +338,10 @@ namespace FFXIVClassic_Map_Server.Actors
{
lock (mActorList)
{
foreach (Actor a in mActorList.Values)
foreach (Player player in mActorList.Values.OfType<Player>())
{
if (a is Player)
{
if (((Player)a).customDisplayName.ToLower().Equals(name.ToLower()))
return (Player)a;
}
if (player.customDisplayName.ToLower().Equals(name.ToLower()))
return player;
}
return null;
}
@ -369,19 +377,22 @@ namespace FFXIVClassic_Map_Server.Actors
}
// 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)
{
List<Actor> actorList = new List<Actor>(mActorList.Count);
foreach (var actor in mActorList.Values)
{
actorList.Add(actor);
}
List<T> actorList = new List<T>(mActorList.Count);
actorList.AddRange(mActorList.Values.OfType<T>());
return actorList;
}
}
public virtual List<Actor> GetAllActors()
{
return GetAllActors<Actor>();
}
public void BroadcastPacketsAroundActor(Actor actor, List<SubPacket> packets)
{
foreach (SubPacket packet in packets)

View File

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

View File

@ -5,6 +5,8 @@ using System.Text;
using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors;
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/
@ -67,6 +69,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{
private Character owner;
private Character target;
private Character masterTarget; // if target is a pet, this is the owner
private TargetFindCharacterType findType;
private TargetFindFlags findFlags;
private TargetFindAOEType aoeType;
@ -128,19 +131,48 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
/// <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)
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
if ((aoeType & TargetFindAOEType.Circle) != 0 && radiusType != TargetFindAOERadiusType.Self)
this.targetPosition = owner.GetPosAsVector3();
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)
{
FindWithinBox(withPet);
@ -149,6 +181,10 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
{
FindWithinCircle(withPet);
}
else if (aoeType == TargetFindAOEType.Cone)
{
FindWithinCone(withPet);
}
}
/// <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
// 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 angle = Vector3.GetAngle(myPos, targetPosition);
@ -174,12 +210,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
var targetCorner = 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
if (actor is Player || actor is BattleNpc)
{
if (actor.GetPosAsVector3().IsWithinBox(myCorner2, targetCorner))
if (actor.GetPosAsVector3().IsWithinBox(targetCorner2, myCorner))
{
if (CanTarget(actor))
AddTarget(actor, withPet);
@ -196,18 +232,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
/// </summary>
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);
}
}
}
private void FindWithinCone(bool withPet)
{
}
private void AddTarget(Character target, bool withPet)
{
if (CanTarget(target))
@ -220,11 +261,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
private void AddAllInParty(Character target, bool withPet)
{
// todo:
AddTarget(target, withPet);
}
private void AddAllInAlliance(Character target, bool withPet)
{
// todo:
AddTarget(target, withPet);
}
public bool CanTarget(Character target)
@ -241,8 +284,32 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai
if (target is Player && ((Player)target).playerSession.isUpdatesLocked)
return false;
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.Text;
using System.Threading.Tasks;
using FFXIVClassic_Map_Server.Actors;
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;
}
}
}