From 91628788831b15d1f9316e26d0428d2d164ede1f Mon Sep 17 00:00:00 2001 From: Niko Date: Thu, 20 Nov 2025 13:36:07 +0000 Subject: [PATCH] Implement Skirmisher armor set bonus --- Content/Buffs/Debuffs/ThermalMarkDebuff.cs | 25 ++++ Content/Buffs/Debuffs/ThermalMarkDebuff.png | Bin 0 -> 3042 bytes Content/GlobalNPCs/ThermalMarkGlobalNPC.cs | 26 +++++ .../AvaliSkirmisherSet/AvaliSkirmisherCowl.cs | 5 +- .../AvaliSkirmisherHelmet.cs | 3 +- .../AvaliSkirmisherSet/AvaliSkirmisherHood.cs | 3 +- .../AvaliSkirmisherSet/AvaliSkirmisherMask.cs | 3 +- Content/Players/AvaliSkirmisherPlayer.cs | 63 +++++++++++ .../Projectiles/Avali/AvaliThermalDrone.cs | 107 ++++++++++++++++++ .../Projectiles/Avali/AvaliThermalDrone.png | Bin 0 -> 504 bytes .../en-US_Mods.ForgottenWawiTech.hjson | 6 + 11 files changed, 237 insertions(+), 4 deletions(-) create mode 100644 Content/Buffs/Debuffs/ThermalMarkDebuff.cs create mode 100644 Content/Buffs/Debuffs/ThermalMarkDebuff.png create mode 100644 Content/GlobalNPCs/ThermalMarkGlobalNPC.cs create mode 100644 Content/Players/AvaliSkirmisherPlayer.cs create mode 100644 Content/Projectiles/Avali/AvaliThermalDrone.cs create mode 100644 Content/Projectiles/Avali/AvaliThermalDrone.png diff --git a/Content/Buffs/Debuffs/ThermalMarkDebuff.cs b/Content/Buffs/Debuffs/ThermalMarkDebuff.cs new file mode 100644 index 0000000..5baeb46 --- /dev/null +++ b/Content/Buffs/Debuffs/ThermalMarkDebuff.cs @@ -0,0 +1,25 @@ +using Terraria; +using Terraria.ID; +using Terraria.ModLoader; +using ForgottenWawiTech.Content.GlobalNPCs; + +namespace ForgottenWawiTech.Content.Buffs.Debuffs +{ + public class ThermalMarkDebuff : ModBuff + { + public override void SetStaticDefaults() + { + Main.debuff[Type] = true; + Main.pvpBuff[Type] = true; + Main.buffNoSave[Type] = true; + BuffID.Sets.LongerExpertDebuff[Type] = true; + BuffID.Sets.NurseCannotRemoveDebuff[Type] = true; + } + + public override void Update(NPC npc, ref int buffIndex) + { + npc.GetGlobalNPC().ThermalMarked = true; + Lighting.AddLight(npc.Center, 0.9f, 0.45f, 0.2f); + } + } +} diff --git a/Content/Buffs/Debuffs/ThermalMarkDebuff.png b/Content/Buffs/Debuffs/ThermalMarkDebuff.png new file mode 100644 index 0000000000000000000000000000000000000000..725a7409e2461e3caba904bfd118bfd33c5ffa95 GIT binary patch literal 3042 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 literal 0 HcmV?d00001 diff --git a/Content/GlobalNPCs/ThermalMarkGlobalNPC.cs b/Content/GlobalNPCs/ThermalMarkGlobalNPC.cs new file mode 100644 index 0000000..92cf7e7 --- /dev/null +++ b/Content/GlobalNPCs/ThermalMarkGlobalNPC.cs @@ -0,0 +1,26 @@ +using Terraria; +using Terraria.ModLoader; +using ForgottenWawiTech.Content.Buffs.Debuffs; + +namespace ForgottenWawiTech.Content.GlobalNPCs +{ + public class ThermalMarkGlobalNPC : GlobalNPC + { + public bool ThermalMarked { get; set; } + + public override bool InstancePerEntity => true; + + public override void ResetEffects(NPC npc) + { + ThermalMarked = false; + } + + public override void ModifyIncomingHit(NPC npc, ref NPC.HitModifiers modifiers) + { + if (npc.HasBuff(ModContent.BuffType())) + { + modifiers.FinalDamage *= 1.12f; + } + } + } +} diff --git a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherCowl.cs b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherCowl.cs index 53adc3b..95f0f5a 100644 --- a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherCowl.cs +++ b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherCowl.cs @@ -4,6 +4,9 @@ using Terraria.ModLoader; using ForgottenWawiTech.Content.Items.Materials; using ForgottenWawiTech.Content.Rarities; using ForgottenWawiTech.Content.Items.Armor.AvaliScoutSet; +using ForgottenWawiTech.Content.Players; + +// Pre-hardmode namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet { @@ -36,7 +39,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet player.setBonus = "Summons thermal vision drones that mark enemies\nMarked enemies take 12% more damage\n+2 max minions and +20% summon damage"; player.maxMinions += 2; player.GetDamage(DamageClass.Summon) += 0.20f; - // TODO: Implement thermal vision drone marking system + player.GetModPlayer().EnableThermalDrones(); } public override void AddRecipes() diff --git a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHelmet.cs b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHelmet.cs index 6d6d8a3..3686874 100644 --- a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHelmet.cs +++ b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHelmet.cs @@ -4,6 +4,7 @@ using Terraria.ModLoader; using ForgottenWawiTech.Content.Items.Materials; using ForgottenWawiTech.Content.Rarities; using ForgottenWawiTech.Content.Items.Armor.AvaliScoutSet; +using ForgottenWawiTech.Content.Players; namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet { @@ -37,7 +38,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet player.setBonus = "Summons thermal vision drones that mark enemies\nMarked enemies take 12% more damage\n+15% melee damage and speed"; player.GetDamage(DamageClass.Melee) += 0.15f; player.GetAttackSpeed(DamageClass.Melee) += 0.15f; - // TODO: Implement thermal vision drone marking system + player.GetModPlayer().EnableThermalDrones(); } public override void AddRecipes() diff --git a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHood.cs b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHood.cs index b5ab86c..0b0aa84 100644 --- a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHood.cs +++ b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherHood.cs @@ -4,6 +4,7 @@ using Terraria.ModLoader; using ForgottenWawiTech.Content.Items.Materials; using ForgottenWawiTech.Content.Rarities; using ForgottenWawiTech.Content.Items.Armor.AvaliScoutSet; +using ForgottenWawiTech.Content.Players; namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet { @@ -37,7 +38,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet player.setBonus = "Summons thermal vision drones that mark enemies\nMarked enemies take 12% more damage\n+20% magic damage and -15% mana cost"; player.GetDamage(DamageClass.Magic) += 0.20f; player.manaCost -= 0.15f; - // TODO: Implement thermal vision drone marking system + player.GetModPlayer().EnableThermalDrones(); } public override void AddRecipes() diff --git a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherMask.cs b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherMask.cs index 12010f3..ce77d4a 100644 --- a/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherMask.cs +++ b/Content/Items/Armor/AvaliSkirmisherSet/AvaliSkirmisherMask.cs @@ -4,6 +4,7 @@ using Terraria.ModLoader; using ForgottenWawiTech.Content.Items.Materials; using ForgottenWawiTech.Content.Rarities; using ForgottenWawiTech.Content.Items.Armor.AvaliScoutSet; +using ForgottenWawiTech.Content.Players; namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet { @@ -36,7 +37,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet player.setBonus = "Summons thermal vision drones that mark enemies\nMarked enemies take 12% more damage\n+18% ranged damage and critical strike chance"; player.GetDamage(DamageClass.Ranged) += 0.18f; player.GetCritChance(DamageClass.Ranged) += 18; - // TODO: Implement thermal vision drone marking system + player.GetModPlayer().EnableThermalDrones(); } public override void AddRecipes() diff --git a/Content/Players/AvaliSkirmisherPlayer.cs b/Content/Players/AvaliSkirmisherPlayer.cs new file mode 100644 index 0000000..328c2ac --- /dev/null +++ b/Content/Players/AvaliSkirmisherPlayer.cs @@ -0,0 +1,63 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.ID; +using Terraria.ModLoader; +using ForgottenWawiTech.Content.Projectiles.Avali; + +namespace ForgottenWawiTech.Content.Players +{ + public class AvaliSkirmisherPlayer : ModPlayer + { + private const int DroneCount = 2; + private const float SpawnRadius = 60f; + + public bool ThermalDronesActive { get; private set; } + + public override void ResetEffects() + { + ThermalDronesActive = false; + } + + public void EnableThermalDrones() + { + ThermalDronesActive = true; + } + + public override void PostUpdate() + { + if (!ThermalDronesActive) + { + return; + } + + if (Player.whoAmI != Main.myPlayer) + { + return; + } + + int droneType = ModContent.ProjectileType(); + int owned = Player.ownedProjectileCounts[droneType]; + if (owned >= DroneCount) + { + return; + } + + var source = Player.GetSource_Misc("AvaliSkirmisherSet"); + for (int i = owned; i < DroneCount; i++) + { + float rotationOffset = MathHelper.TwoPi * i / DroneCount; + Vector2 spawnPos = Player.Center + rotationOffset.ToRotationVector2() * SpawnRadius; + Projectile.NewProjectile( + source, + spawnPos, + Vector2.Zero, + droneType, + 0, + 0f, + Player.whoAmI, + i, + DroneCount); + } + } + } +} diff --git a/Content/Projectiles/Avali/AvaliThermalDrone.cs b/Content/Projectiles/Avali/AvaliThermalDrone.cs new file mode 100644 index 0000000..b930af2 --- /dev/null +++ b/Content/Projectiles/Avali/AvaliThermalDrone.cs @@ -0,0 +1,107 @@ +using Microsoft.Xna.Framework; +using Terraria; +using Terraria.ID; +using Terraria.ModLoader; +using ForgottenWawiTech.Content.Buffs.Debuffs; +using ForgottenWawiTech.Content.Players; + +namespace ForgottenWawiTech.Content.Projectiles.Avali +{ + public class AvaliThermalDrone : ModProjectile + { + private const float OrbitSpeed = 0.06f; + private const float OrbitRadius = 72f; + private const int MarkCooldown = 45; + private const float MarkRange = 700f; + + public override void SetStaticDefaults() + { + ProjectileID.Sets.MinionSacrificable[Type] = false; + ProjectileID.Sets.MinionShot[Type] = true; + } + + public override void SetDefaults() + { + Projectile.width = 26; + Projectile.height = 26; + Projectile.friendly = true; + Projectile.DamageType = DamageClass.Summon; + Projectile.penetrate = -1; + Projectile.tileCollide = false; + Projectile.ignoreWater = true; + Projectile.timeLeft = 2; + Projectile.netImportant = true; + Projectile.minion = true; + Projectile.minionSlots = 0f; + } + + public override void AI() + { + Player owner = Main.player[Projectile.owner]; + AvaliSkirmisherPlayer modPlayer = owner.GetModPlayer(); + if (!owner.active || owner.dead || !modPlayer.ThermalDronesActive) + { + Projectile.Kill(); + return; + } + + Projectile.timeLeft = 2; + + float index = Projectile.ai[0]; + float total = Projectile.ai[1]; + if (total <= 0f) + { + total = 2f; + } + + float rotation = (Main.GameUpdateCount * OrbitSpeed) + index * MathHelper.TwoPi / total; + Vector2 offset = rotation.ToRotationVector2() * OrbitRadius; + Projectile.Center = owner.Center + offset; + Projectile.velocity = owner.velocity; + + Lighting.AddLight(Projectile.Center, 0.55f, 0.2f, 0.15f); + + if (Projectile.localAI[0]++ >= MarkCooldown) + { + Projectile.localAI[0] = 0f; + if (Projectile.owner == Main.myPlayer) + { + NPC target = FindTarget(Projectile.Center, MarkRange); + if (target != null) + { + target.AddBuff(ModContent.BuffType(), 300); + Vector2 burstDirection = (target.Center - Projectile.Center).SafeNormalize(Vector2.UnitY); + for (int i = 0; i < 6; i++) + { + Dust dust = Dust.NewDustDirect(Projectile.Center, 0, 0, DustID.Torch, burstDirection.X * 4f, burstDirection.Y * 4f, 120, default, 1.1f); + dust.noGravity = true; + } + } + } + } + } + + private static NPC FindTarget(Vector2 center, float range) + { + NPC selected = null; + float sqrRange = range * range; + for (int i = 0; i < Main.maxNPCs; i++) + { + NPC npc = Main.npc[i]; + if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0) + { + continue; + } + + float dist = Vector2.DistanceSquared(center, npc.Center); + if (dist < sqrRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0)) + { + sqrRange = dist; + selected = npc; + } + } + + return selected; + } + } +} diff --git a/Content/Projectiles/Avali/AvaliThermalDrone.png b/Content/Projectiles/Avali/AvaliThermalDrone.png new file mode 100644 index 0000000000000000000000000000000000000000..9e0cf81e52f4133dbe85453dd9a37993af17b5be GIT binary patch literal 504 zcmeAS@N?(olHy`uVBq!ia0vp^0U*r53?z4+XPOVBbOU@sT!FNbf{DF-NtsjE_3B;! z|NjSy0D+K@p01v+t9x8zR#D@WS?dlQ`1+YJESG!@x4dC7*`C93=UXkhhvvt!hjSLlJ~RwmnP~Bh_e#*cGOJz5H)U2RZk=*d{>S{o z|7E^K_FWXNcxrjXh&wV*Hfp0Ti%!ljhM&t`NT+&77>M@wN(xASbQfH=B6&8`PK|k& o(pT;d?|57xzrgJ7^Ax@sCjQeEzP*#>W`d&2)78&qol`;+07t#pIRF3v literal 0 HcmV?d00001 diff --git a/Localization/en-US_Mods.ForgottenWawiTech.hjson b/Localization/en-US_Mods.ForgottenWawiTech.hjson index 37e4b78..9cad27d 100644 --- a/Localization/en-US_Mods.ForgottenWawiTech.hjson +++ b/Localization/en-US_Mods.ForgottenWawiTech.hjson @@ -991,6 +991,7 @@ Projectiles: { TranscendentBladeShard.DisplayName: Transcendent Blade Shard TranscendentNova.DisplayName: Transcendent Nova TranscendentRailBolt.DisplayName: Transcendent Rail Bolt + AvaliThermalDrone.DisplayName: Avali Thermal Drone } Prefixes: { @@ -1003,4 +1004,9 @@ Buffs: { DisplayName: Nullified Description: Your wings feel heavy and unresponsive, alongside a general sense of numbness. } + + ThermalMarkDebuff: { + DisplayName: Thermal Mark + Description: You are tagged by Avali thermal drones, making you vulnerable. + } }