public override void AI() { rotationFrame = (rotationFrame + 1) % rotationFrames; float startAngle = -2f * (float)Math.PI * rotationFrame / rotationFrames; MinionPathfindingPlayer player = Main.player[projectile.owner].GetModPlayer <MinionPathfindingPlayer>(); bool isMyPlayer = Main.myPlayer == player.player.whoAmI; BlockAwarePathfinder pathfinder = player.GetPathfinder((int)projectile.ai[0]); if (pathfinder.searchSucceeded || !pathfinder.searchFailed) { int radius = isMyPlayer ? pathfinder.searchSucceeded ? 12 : 6 : 8; Color color = GetWaypointColor(player); float scale = isMyPlayer ? pathfinder.searchSucceeded ? 1.2f : 0.8f : 1f; for (int i = 0; i < 3; i++) { float angle = startAngle + i * 2 * (float)Math.PI / 3; Vector2 pos = projectile.Center + radius * angle.ToRotationVector2(); Dust.NewDust(pos, 1, 1, DustType <MinionWaypointDust>(), newColor: color, Scale: scale); } } else if (pathfinder.searchFailed) { for (int i = 0; i < 2; i++) { float offset = 12 * (i == 0 ? (float)Math.Sin(startAngle) : (float)Math.Cos(startAngle)); Vector2 pos = projectile.Center + new Vector2(i == 1 ? offset : -offset, offset); Dust.NewDust(pos, 1, 1, DustType <MinionWaypointDust>(), newColor: Color.Red, Scale: 1.2f); } } }
internal Color GetWaypointColor(MinionPathfindingPlayer player) { bool isMyPlayer = Main.myPlayer == player.player.whoAmI; bool suceeded = isMyPlayer && player.GetPathfinder((int)projectile.ai[0]).searchSucceeded&& player.InWaypointRange(projectile.Center); if (isMyPlayer) { if (!suceeded) { return(Color.Gray); } bool isActive = player.CurrentTacticsGroup == projectile.ai[0] || player.CurrentTacticsGroup == 2; Color color = MinionPathfindingPlayer.WaypointColors[(int)projectile.ai[0]]; if (isActive) { return(color); } else { return(Color.Multiply(color, 0.5f)); } } else { return((projectile.ai[0] == 0 ? Color.Aquamarine : Color.Lavender) * 0.5f); } }
public Vector2?SelectedEnemyInRange(float maxRange, float noLOSRange = 0, bool maxRangeFromPlayer = true, Vector2?losCenter = null) { Vector2 losCenterVector = losCenter ?? projectile.Center; currentTactic = player.GetModPlayer <MinionTacticsPlayer>().GetTacticForMinion(this); MinionPathfindingPlayer pathfindingPlayer = player.GetModPlayer <MinionPathfindingPlayer>(); // to cut back on Line-of-Sight computations, always chase the same NPC for some number of frames once one has been found if (targetNPCIndex is int idx && Main.npc[idx].active && targetNPCCacheFrames++ < currentTactic.TargetCacheFrames) { return(Main.npc[idx].Center); } Vector2 rangeCheckCenter; BlockAwarePathfinder pathfinder = pathfindingPlayer.GetPathfinder(this); Vector2 waypointPos = pathfindingPlayer.GetWaypointPosition(this); if (!maxRangeFromPlayer) { rangeCheckCenter = projectile.Center; } else if (!pathfinder.InProgress() && pathfinder.searchSucceeded && waypointPos != default) { rangeCheckCenter = waypointPos; } else { rangeCheckCenter = player.Center; } List <NPC> possibleTargets = new List <NPC>(); for (int i = 0; i < Main.maxNPCs; i++) { NPC npc = Main.npc[i]; if (ShouldIgnoreNPC(npc)) { continue; } bool inRange = Vector2.DistanceSquared(npc.Center, rangeCheckCenter) < maxRange * maxRange; bool inNoLOSRange = Vector2.DistanceSquared(npc.Center, player.Center) < noLOSRange * noLOSRange; bool lineOfSight = inNoLOSRange || (inRange && Collision.CanHitLine(losCenterVector, 1, 1, npc.position, npc.width, npc.height)); if (inNoLOSRange || (lineOfSight && inRange)) { possibleTargets.Add(npc); } } NPC chosen = currentTactic.ChooseTargetFromList(projectile, possibleTargets); if (chosen != default) { targetNPCIndex = chosen.whoAmI; targetNPCCacheFrames = 0; return(chosen.Center); } else { return(null); } }