mirror of
				https://bitbucket.org/Ioncannon/project-meteor-server.git
				synced 2025-05-20 08:26:59 -04:00 
			
		
		
		
	cleaned targetfind some
- added character allegiance types
This commit is contained in:
		| @@ -10,7 +10,16 @@ using System; | ||||
|  | ||||
| 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 COLORINFO = 1; | ||||
| @@ -66,6 +75,8 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|         public AIContainer aiContainer; | ||||
|         public StatusEffects statusEffects; | ||||
|  | ||||
|         public CharacterTargetingAllegiance allegiance; | ||||
|  | ||||
|         public Character(uint actorID) : base(actorID) | ||||
|         {             | ||||
|             //Init timer array to "notimer" | ||||
|   | ||||
| @@ -18,7 +18,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai | ||||
|     { | ||||
|         None, | ||||
|         /// <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> | ||||
|         Alliance, | ||||
|         /// <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>(); | ||||
|         } | ||||
|  | ||||
|         public List<T> GetTargets<T>() where T : Character | ||||
|         { | ||||
|             return new List<T>(targets.OfType<T>()); | ||||
|         } | ||||
|  | ||||
|         public List<Character> GetTargets() | ||||
|         { | ||||
|             return targets; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Call this before <see cref="FindWithinArea"/> <para/> | ||||
|         /// </summary> | ||||
| @@ -131,11 +141,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai | ||||
|         /// <para> Call SetAOEType before calling this </para> | ||||
|         /// Find targets within area set by <see cref="SetAOEType"/> | ||||
|         /// </summary> | ||||
|  | ||||
|         public void FindWithinArea(Character target, TargetFindFlags flags) | ||||
|         { | ||||
|             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) | ||||
| @@ -143,10 +151,13 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai | ||||
|             else | ||||
|                 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 | ||||
|             bool withPet = (flags & TargetFindFlags.Pets) != 0 || masterTarget.currentSubState != owner.currentSubState; | ||||
|             bool withPet = (flags & TargetFindFlags.Pets) != 0 || masterTarget.allegiance != owner.allegiance; | ||||
|  | ||||
|             if (IsPlayer(owner)) | ||||
|             { | ||||
| @@ -170,83 +181,63 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai | ||||
|                 else | ||||
|                 { | ||||
|                     findType = TargetFindCharacterType.PlayerToBattleNpc; | ||||
|                      | ||||
|                     AddAllBattleNpcs(masterTarget, false); | ||||
|                 } | ||||
|             } | ||||
|             if (aoeType == TargetFindAOEType.Box) | ||||
|             else | ||||
|             { | ||||
|                 FindWithinBox(withPet); | ||||
|             } | ||||
|             else if (aoeType == TargetFindAOEType.Circle) | ||||
|             { | ||||
|                 FindWithinCircle(withPet); | ||||
|             } | ||||
|             else if (aoeType == TargetFindAOEType.Cone) | ||||
|             { | ||||
|                 FindWithinCone(withPet); | ||||
|                 // todo: this needs checking.. | ||||
|                 if (masterTarget is Player || owner.allegiance == CharacterTargetingAllegiance.Player) | ||||
|                     findType = TargetFindCharacterType.BattleNpcToPlayer; | ||||
|                 else | ||||
|                     findType = TargetFindCharacterType.BattleNpcToBattleNpc; | ||||
|  | ||||
|                 // todo: configurable pet aoe buff | ||||
|                 if (findType == TargetFindCharacterType.BattleNpcToBattleNpc && TryGetMasterTarget(target) != null) | ||||
|                     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> | ||||
|         /// 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) | ||||
|         private bool IsWithinBox(Character target, 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 | ||||
|             var myPos = owner.GetPosAsVector3(); | ||||
|             var angle = Vector3.GetAngle(myPos, targetPosition); | ||||
|  | ||||
|                 // todo: make the distance check modifiable | ||||
|                 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); | ||||
|             // todo: actually check this works.. | ||||
|             var myCorner = myPos.NewHorizontalVector(angle, extents); | ||||
|             var myCorner2 = myPos.NewHorizontalVector(angle, -extents); | ||||
|  | ||||
|                 // 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); | ||||
|  | ||||
|                 var targetCorner = targetPosition.NewHorizontalVector(angle, extents); | ||||
|                 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); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return target.GetPosAsVector3().IsWithinBox(targetCorner2, myCorner); | ||||
|         } | ||||
|  | ||||
|         /// <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) | ||||
|         private bool IsWithinCone(Character target, bool withPet) | ||||
|         { | ||||
|             var actors = (findFlags & TargetFindFlags.ZoneWide) != 0 ? owner.zone.GetAllActors<Character>() : owner.zone.GetActorsAroundActor<Character>(owner, 70); | ||||
|  | ||||
|             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) | ||||
|         { | ||||
|              | ||||
|             // todo: | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         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) | ||||
|         { | ||||
|             // todo: | ||||
|             /* | ||||
|              * foreach (var actor in target.currentParty.GetMembers()) | ||||
|              * { | ||||
|              *     AddTarget(actor, withPet); | ||||
|              * } | ||||
|              */ | ||||
|             AddTarget(target, withPet); | ||||
|         } | ||||
|  | ||||
|         private void AddAllInAlliance(Character target, bool withPet) | ||||
|         { | ||||
|             // todo: | ||||
|             /* | ||||
|              * foreach (var actor in target.currentParty.GetAllianceMembers()) | ||||
|              * { | ||||
|              *     AddTarget(actor, 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 | ||||
|             if (targets.Contains(target)) | ||||
| @@ -280,13 +316,23 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai | ||||
|             if ((findFlags & TargetFindFlags.Dead) == 0 && target.IsDead()) | ||||
|                 return false; | ||||
|  | ||||
|             // cant target if player is zoning | ||||
|             if (target is Player && ((Player)target).playerSession.isUpdatesLocked) | ||||
|             bool targetingPlayer = target is Player; | ||||
|              | ||||
|             // cant target if zoning | ||||
|             if (target.isZoning || owner.isZoning || target.zone != owner.zone || targetingPlayer && ((Player)target).playerSession.isUpdatesLocked) | ||||
|                 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) | ||||
| @@ -295,21 +341,30 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai | ||||
|                 return true; | ||||
|  | ||||
|             // 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 (target.aiContainer != null) | ||||
|             { | ||||
|                 var controller = target.aiContainer.GetController(); | ||||
|                 if (controller != null && controller is PetController) | ||||
|                 { | ||||
|                     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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -62,6 +62,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.ai.controllers | ||||
|         public void SetPetMaster(Character master) | ||||
|         { | ||||
|             petMaster = master; | ||||
|  | ||||
|             if (master is Player) | ||||
|                 owner.allegiance = CharacterTargetingAllegiance.Player; | ||||
|             else | ||||
|                 owner.allegiance = CharacterTargetingAllegiance.BattleNpcs; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -24,6 +24,7 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             this.aiContainer = new AIContainer(this, new BattleNpcController(this), new PathFind(this), new TargetFind(this)); | ||||
|             this.currentSubState = SetActorStatePacket.SUB_STATE_MONSTER; | ||||
|             this.hateContainer = new HateContainer(this); | ||||
|             this.allegiance = CharacterTargetingAllegiance.BattleNpcs; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|                     ushort actorState, uint animationId, string 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.hateContainer = new HateContainer(this); | ||||
|         } | ||||
|   | ||||
| @@ -251,6 +251,7 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             lastPlayTimeUpdate = Utils.UnixTimeStampUTC(); | ||||
|  | ||||
|             this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this)); | ||||
|             allegiance = CharacterTargetingAllegiance.Player; | ||||
|         } | ||||
|          | ||||
|         public List<SubPacket> Create0x132Packets() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user