internal void SetupPathfinderMetas() { // these values don't like being initialized in Initialize() for some reason myTacticsPlayer = player.GetModPlayer <MinionTacticsPlayer>(); pathfinderMetas = new PathfinderMetadata[MinionTacticsPlayer.TACTICS_GROUPS_COUNT]; for (int i = 0; i < MinionTacticsPlayer.TACTICS_GROUPS_COUNT; i++) { pathfinderMetas[i] = new PathfinderMetadata(this, i); } for (int i = 0; i < Main.maxPlayers; i++) { Player p = Main.player[i]; if (p.active) { MinionPathfindingPlayer pathPlayer = p.GetModPlayer <MinionPathfindingPlayer>(); } } }
public override void ModifyHitNPC(Projectile projectile, NPC target, ref int damage, ref float knockback, ref bool crit, ref int hitDirection) { // nerf all minion damage, even if they're not following the waypoint. Maybe a bit iffy if (!(projectile.minion || ProjectileID.Sets.MinionShot[projectile.type])) { return; } MinionPathfindingPlayer player = Main.player[projectile.owner].GetModPlayer <MinionPathfindingPlayer>(); // no falloff if waypoint not placed if (player.pathfinderMetas.All(m => m.WaypointPosition == default)) { return; } float maxDist = player.WaypointPlacementRange; float damageReduction = player.WaypointDamageFalloff * Math.Min(maxDist, Vector2.Distance(projectile.Center, player.player.Center)) / maxDist; damage = (int)((1 - damageReduction) * damage); }
internal BlockAwarePathfinder(MinionPathfindingPlayer player, int tacticsGroup) { modPlayer = player; this.tacticsGroup = tacticsGroup; }
internal PathfinderMetadata(MinionPathfindingPlayer player, int tacticsGroup) { pHelper = new BlockAwarePathfinder(player, tacticsGroup); }
internal Vector2?NextPathfindingTarget() { // initialize late to avoid any lifecycle issues if (pathfinder is null) { Setup(); DetachFromPath(); } // need to re-check that we haven't been assigned to a different pathfinder SetPathfinder(); if (pathfinder.searchFailed || pathfinder.waypointPosition == default) { DetachFromPath(); return(null); } else if (pathfinder.InProgress()) { DetachFromPath(); // idle while the algorithm is still running return(pathfinder.playerPlacedWaypoint ? (Vector2?)Vector2.Zero : null); } // simple approach: Go towards a node until you get close enough, then go to the next node List <Vector2> path = pathfinder.orderedPath; if (nodeIndex > path.Count - 1 || nodeIndex < 0) { AttachToPath(); } Vector2 currentNode = path.ElementAtOrDefault(nodeIndex); if (currentNode == default) { DetachFromPath(); return(null); } if (Vector2.DistanceSquared(projectile.Center, currentNode) < nodeProximity * nodeProximity) { nodeIndex = Math.Min(path.Count - 1, nodeIndex + 1); } if (Math.Abs(projectile.velocity.Length()) < NO_PROGRESS_THRESHOLD) { noProgressFrames++; } if (noProgressFrames > 5) { isStuck = true; } // make sure the target exceeds a certain lenght threshold, // so the AI will speed up the minions Vector2 target = currentNode - projectile.position; // we're at the waypoint, rotate around it if (nodeIndex == path.Count - 1 && Vector2.Distance(projectile.Center, currentNode) < MinionPathfindingPlayer.WAYPOINT_PROXIMITY_THRESHOLD) { MinionPathfindingPlayer owner = Main.player[projectile.owner].GetModPlayer <MinionPathfindingPlayer>(); List <Projectile> minionsAtWaypoint = owner.GetMinionsAtWaypoint(minion); if (minionsAtWaypoint.Count > 0) { float animationAngle = MathHelper.TwoPi * (Main.GameUpdateCount % 120) / 120f; animationAngle += MathHelper.TwoPi * minionsAtWaypoint.IndexOf(projectile) / (float)minionsAtWaypoint.Count; target += Math.Min(48, 24 + 2 * minionsAtWaypoint.Count) * animationAngle.ToRotationVector2(); } } else if (target.Length() < 16) { // bump the minimum target distance up to 16, some idle AIs move too slowly otherwise target.SafeNormalize(); target *= 16; } modifyPath?.Invoke(ref target); return(target); }