using Microsoft.Xna.Framework; using Terraria; using Terraria.Audio; using Terraria.ID; using Terraria.ModLoader; namespace ForgottenWawiTech.Content.Projectiles.FragmentedPrism { public class FragmentedPrismShard : ModProjectile { private const float OrbitRadius = 72f; private const float BaseOrbitSpeed = 0.04f; private const int FireInterval = 1; private const int VisualSpawnInterval = 18; private ref float ShardIndex => ref Projectile.ai[0]; private ref float OrbitAngleOffset => ref Projectile.ai[1]; private ref float FireTimer => ref Projectile.localAI[0]; private ref float VisualTimer => ref Projectile.localAI[1]; public override void SetStaticDefaults() { Main.projFrames[Type] = 5; } public override void SetDefaults() { Projectile.width = 22; Projectile.height = 22; Projectile.friendly = false; Projectile.hostile = false; Projectile.penetrate = -1; Projectile.tileCollide = false; Projectile.ignoreWater = true; Projectile.timeLeft = 2; Projectile.hide = false; } public override bool? CanDamage() => false; public override void AI() { Player player = Main.player[Projectile.owner]; if (!player.active || player.dead) { Projectile.Kill(); return; } int itemType = ModContent.ItemType(); if (player.HeldItem.type != itemType) { Projectile.Kill(); return; } if (OrbitAngleOffset == 0f && ShardIndex >= 0f) { OrbitAngleOffset = MathHelper.TwoPi * (ShardIndex / FragmentedPrismController.ShardCount); } if (!TryGetController(player, out Projectile controller)) { Projectile.Kill(); return; } float chargeTimer = controller.ai[1]; float chargeProgress = FragmentedPrismController.MaxChargeTime > 0f ? MathHelper.Clamp(chargeTimer / FragmentedPrismController.MaxChargeTime, 0f, 1f) : 0f; int firingShardCount = (int)MathHelper.Clamp(chargeTimer / FragmentedPrismController.ChargeTimePerShard, 0f, FragmentedPrismController.ShardCount); bool canFire = ShardIndex < firingShardCount; float orbitSpeed = BaseOrbitSpeed + chargeProgress * 0.06f; float orbitRadius = OrbitRadius + chargeProgress * 12f; float rotation = (float)(Main.GameUpdateCount * orbitSpeed) + OrbitAngleOffset; Vector2 desiredPosition = player.Center + rotation.ToRotationVector2() * orbitRadius; Projectile.Center = desiredPosition; Vector2 aim = Main.MouseWorld - Projectile.Center; if (aim.LengthSquared() < 0.001f) { aim = Vector2.UnitX * player.direction; } Projectile.rotation = aim.ToRotation() + MathHelper.PiOver2; Projectile.spriteDirection = -1; if (canFire && Main.netMode != NetmodeID.Server) { VisualTimer++; if (VisualTimer >= VisualSpawnInterval) { VisualTimer = 0f; SpawnBlackHoleVisual(player); } } else { VisualTimer = 0f; } Animate(); if (Projectile.owner != Main.myPlayer) { Projectile.timeLeft = 10; return; } if (canFire) { FireTimer++; if (FireTimer >= FireInterval) { FireTimer = 0f; FireBeam(player); } } else { FireTimer = 0f; } Projectile.timeLeft = 10; } private void Animate() { Projectile.frameCounter++; if (Projectile.frameCounter >= 6) { Projectile.frameCounter = 0; Projectile.frame = (Projectile.frame + 1) % Main.projFrames[Type]; } } private void FireBeam(Player player) { Vector2 aimDirection = Main.MouseWorld - Projectile.Center; if (aimDirection.LengthSquared() < 4f) { aimDirection = Vector2.UnitX * player.direction; } aimDirection.Normalize(); Vector2 velocity = aimDirection * 30f; int beamType = ModContent.ProjectileType(); int damage = Projectile.originalDamage > 0 ? Projectile.originalDamage : player.GetWeaponDamage(player.HeldItem); float knockBack = player.GetWeaponKnockback(player.HeldItem, player.HeldItem.knockBack); Projectile.NewProjectile(Projectile.GetSource_FromThis(), Projectile.Center, velocity, beamType, damage, knockBack, player.whoAmI); SoundEngine.PlaySound(SoundID.Item91 with { Volume = 0.2f, Pitch = 0.55f }, Projectile.Center); } private void SpawnBlackHoleVisual(Player player) { if (Projectile.owner != Main.myPlayer) { return; } int visualType = ModContent.ProjectileType(); Vector2 toMouse = Main.MouseWorld - Projectile.Center; Vector2 offset = toMouse.SafeNormalize(Vector2.UnitY) * -16f; Projectile.NewProjectile(Projectile.GetSource_FromThis(), Projectile.Center + offset, Vector2.Zero, visualType, 0, 0f, Projectile.owner); } private bool TryGetController(Player player, out Projectile controller) { int controllerType = ModContent.ProjectileType(); for (int i = 0; i < Main.maxProjectiles; i++) { Projectile proj = Main.projectile[i]; if (proj.active && proj.owner == player.whoAmI && proj.type == controllerType) { controller = proj; return true; } } controller = null; return false; } } }