From e3f74c2e21a9b6644cc678adf3f35769729c2f08 Mon Sep 17 00:00:00 2001 From: YouHaveTrouble Date: Mon, 22 Dec 2025 17:28:31 +0100 Subject: [PATCH] update to newest tmodloader version --- Buffs/ToclafaneMinionBuff.cs | 23 +- Changes/NPCLoot.cs | 22 +- .../ArcaneMissile.cs} | 23 +- .../ArcaneMissile.png} | Bin .../ArcaneMissileBehavior.cs} | 39 +-- Items/CopperSwordOnAStick.cs | 1 - Items/KatanaRedo.cs | 61 ++-- Items/MithrilPebbleOfPigSmiting.cs | 14 - Items/ToclafaneStaff.cs | 2 - Localization/en-US_Mods.YHTMod.hjson | 56 ++++ .../MithrilPebbleOfPigSmitingProjectile.cs | 2 +- Projectiles/Weapons/ToclafaneMinion.cs | 301 ++++++++++-------- 12 files changed, 304 insertions(+), 240 deletions(-) rename Items/{ArcaneMissle/ArcaneMissle.cs => ArcaneMissile/ArcaneMissile.cs} (62%) rename Items/{ArcaneMissle/ArcaneMissle.png => ArcaneMissile/ArcaneMissile.png} (100%) rename Items/{ArcaneMissle/ArcaneMissleBehavior.cs => ArcaneMissile/ArcaneMissileBehavior.cs} (55%) create mode 100644 Localization/en-US_Mods.YHTMod.hjson diff --git a/Buffs/ToclafaneMinionBuff.cs b/Buffs/ToclafaneMinionBuff.cs index 08703ee..053c799 100644 --- a/Buffs/ToclafaneMinionBuff.cs +++ b/Buffs/ToclafaneMinionBuff.cs @@ -2,23 +2,26 @@ using Terraria; using Terraria.ModLoader; using YHTMod.Projectiles.Weapons; -namespace YHTMod.Buffs; +namespace YHTMod.Buffs; -public class ToclafaneMinionBuff : ModBuff { - - public override void SetStaticDefaults() { - DisplayName.SetDefault("Summon Toclafane"); - Description.SetDefault("It came from a parallel world to fight for its Master."); +public class ToclafaneMinionBuff : ModBuff +{ + public override void SetStaticDefaults() + { Main.buffNoSave[Type] = true; Main.buffNoTimeDisplay[Type] = true; } - public override void Update(Player player, ref int buffIndex) { - if (player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) { + public override void Update(Player player, ref int buffIndex) + { + if (player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) + { player.buffTime[buffIndex] = 18000; - } else { + } + else + { player.DelBuff(buffIndex); buffIndex--; } } -} +} \ No newline at end of file diff --git a/Changes/NPCLoot.cs b/Changes/NPCLoot.cs index 0ef874c..6154d14 100644 --- a/Changes/NPCLoot.cs +++ b/Changes/NPCLoot.cs @@ -1,32 +1,32 @@ - using Terraria; using Terraria.GameContent.ItemDropRules; using Terraria.ID; using Terraria.ModLoader; using YHTMod.Items; -using YHTMod.Items.ArcaneMissle; +using YHTMod.Items.ArcaneMissile; namespace YHTMod.Changes; public class NpcLoot : GlobalNPC { - public override void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) { - int id = npc.type; - - if (NPCID.Sets.CountsAsCritter[id]) { + public override void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) + { + var id = npc.type; + + if (NPCID.Sets.CountsAsCritter[id]) + { npcLoot.Add(ItemDropRule.Common(ModContent.ItemType(), 400)); } - switch (id) { + switch (id) + { case NPCID.Plantera: npcLoot.Add(ItemDropRule.Common(ItemID.ChlorophyteOre, 1, 60, 80)); break; case NPCID.Tim: - npcLoot.Add(ItemDropRule.Common(ModContent.ItemType())); + npcLoot.Add(ItemDropRule.Common(ModContent.ItemType())); break; } - - } -} +} \ No newline at end of file diff --git a/Items/ArcaneMissle/ArcaneMissle.cs b/Items/ArcaneMissile/ArcaneMissile.cs similarity index 62% rename from Items/ArcaneMissle/ArcaneMissle.cs rename to Items/ArcaneMissile/ArcaneMissile.cs index 139e783..0c6471e 100644 --- a/Items/ArcaneMissle/ArcaneMissle.cs +++ b/Items/ArcaneMissile/ArcaneMissile.cs @@ -3,20 +3,17 @@ using Terraria.GameContent.Creative; using Terraria.ID; using Terraria.ModLoader; -namespace YHTMod.Items.ArcaneMissle; +namespace YHTMod.Items.ArcaneMissile; -public class ArcaneMissle : ModItem { - - public override void SetStaticDefaults() { - DisplayName.SetDefault("Arcane Missle"); - Tooltip.SetDefault( - "Magical projectile crits shoot a homing arcane missle\n" + - "Arcane missles cannot crit" - ); +public class ArcaneMissile : ModItem +{ + public override void SetStaticDefaults() + { CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1; } - public override void SetDefaults() { + public override void SetDefaults() + { Item.width = 64; Item.height = 64; Item.accessory = true; @@ -27,10 +24,10 @@ public class ArcaneMissle : ModItem { Item.noUseGraphic = true; } - public override void UpdateAccessory(Player player, bool hideVisual) { - + public override void UpdateAccessory(Player player, bool hideVisual) + { player.GetModPlayer().arcaneMissle = Item.damage; - + base.UpdateAccessory(player, hideVisual); } } \ No newline at end of file diff --git a/Items/ArcaneMissle/ArcaneMissle.png b/Items/ArcaneMissile/ArcaneMissile.png similarity index 100% rename from Items/ArcaneMissle/ArcaneMissle.png rename to Items/ArcaneMissile/ArcaneMissile.png diff --git a/Items/ArcaneMissle/ArcaneMissleBehavior.cs b/Items/ArcaneMissile/ArcaneMissileBehavior.cs similarity index 55% rename from Items/ArcaneMissle/ArcaneMissleBehavior.cs rename to Items/ArcaneMissile/ArcaneMissileBehavior.cs index 5b7c174..09c01de 100644 --- a/Items/ArcaneMissle/ArcaneMissleBehavior.cs +++ b/Items/ArcaneMissile/ArcaneMissileBehavior.cs @@ -1,28 +1,31 @@ -using System; using Terraria; using Terraria.ID; using Terraria.ModLoader; -namespace YHTMod.Items.ArcaneMissle; +namespace YHTMod.Items.ArcaneMissile; -public class ArcaneMissleBehavior : GlobalNPC { - - public override void OnHitByProjectile(NPC npc, Projectile projectile, int damage, float knockback, bool crit) { - if (!crit) { - base.OnHitByProjectile(npc, projectile, damage, knockback, false); +public class ArcaneMissileBehavior : GlobalNPC +{ + public override void OnHitByProjectile(NPC npc, Projectile projectile, NPC.HitInfo hitInfo, int damage) + { + if (!hitInfo.Crit) + { + base.OnHitByProjectile(npc, projectile, hitInfo, damage); return; } - if (Main.netMode == NetmodeID.Server) { + if (Main.netMode == NetmodeID.Server) + { return; } - Player player = Main.LocalPlayer; - - if (player.GetModPlayer().arcaneMissle != 0 && projectile.DamageType == DamageClass.Magic) { - // player just crit with magic weapon while having arcane missle accessory - Projectile proj = Projectile.NewProjectileDirect( - projectile.GetSource_FromThis("arcaneMissle"), + var player = Main.LocalPlayer; + + if (player.GetModPlayer().arcaneMissle != 0 && projectile.DamageType == DamageClass.Magic) + { + // player just crit with magic weapon while having arcane missile accessory + var proj = Projectile.NewProjectileDirect( + projectile.GetSource_FromThis("arcaneMissile"), Main.LocalPlayer.position, npc.position.DirectionFrom(Main.LocalPlayer.position), ProjectileID.MagicMissile, @@ -37,11 +40,11 @@ public class ArcaneMissleBehavior : GlobalNPC { proj.tileCollide = false; proj.DamageType = DamageClass.Magic; proj.aiStyle = ProjAIStyleID.MagicMissile; - - // Prevent crits for the missles - proj.CritChance = Int32.MinValue; + + // Prevent crits for the missiles + proj.CritChance = int.MinValue; } - base.OnHitByProjectile(npc, projectile, damage, knockback, true); + base.OnHitByProjectile(npc, projectile, hitInfo, damage); } } \ No newline at end of file diff --git a/Items/CopperSwordOnAStick.cs b/Items/CopperSwordOnAStick.cs index 3eceb92..31c0ea8 100644 --- a/Items/CopperSwordOnAStick.cs +++ b/Items/CopperSwordOnAStick.cs @@ -7,7 +7,6 @@ namespace YHTMod.Items; public class CopperSwordOnAStick : ModItem { public override void SetStaticDefaults() { - DisplayName.SetDefault("Copper Sword On A Stick"); CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1; } diff --git a/Items/KatanaRedo.cs b/Items/KatanaRedo.cs index 706c381..6e1d6d0 100644 --- a/Items/KatanaRedo.cs +++ b/Items/KatanaRedo.cs @@ -6,52 +6,51 @@ using Terraria.ModLoader; namespace YHTMod.Items; -public class KatanaRedo : GlobalItem { - +public class KatanaRedo : GlobalItem +{ public override void ModifyTooltips(Item item, List tooltips) { if (item.type != ItemID.Katana) return; - tooltips.Insert(5, new TooltipLine(YHTMod.GetInstance(), "flavor" , "Nothing personel kid.")); - tooltips.Insert(6, new TooltipLine(YHTMod.GetInstance(), "usage" , "Right click to teleport behind them.")); + tooltips.Insert(5, new TooltipLine(YHTMod.GetInstance(), "flavor", "Nothing personel kid.")); + tooltips.Insert(6, new TooltipLine(YHTMod.GetInstance(), "usage", "Right click to teleport behind them.")); } - public override bool AltFunctionUse(Item item, Player player) { - if (item.type != ItemID.Katana) { - return base.AltFunctionUse(item, player); - } - return true; + public override bool AltFunctionUse(Item item, Player player) + { + return item.type == ItemID.Katana || base.AltFunctionUse(item, player); } - public override bool? UseItem(Item item, Player player) { + public override bool? UseItem(Item item, Player player) + { if (item.type != ItemID.Katana || player.altFunctionUse != 2) return null; - YhtPlayer yhtPlayer = player.GetModPlayer(); + var yhtPlayer = player.GetModPlayer(); if (yhtPlayer.katanaTeleportCooldown > 0) return null; yhtPlayer.katanaTeleportCooldown = 300; - for (int i = 0; i < Main.maxNPCs; i++) { - NPC npc = Main.npc[i]; + for (var i = 0; i < Main.maxNPCs; i++) + { + var npc = Main.npc[i]; if (!npc.CanBeChasedBy()) continue; - float between = Vector2.Distance(npc.Center, player.Center); - bool inRange = between < 650; - - bool lineOfSight = Collision.CanHitLine(player.position, player.width, player.height, npc.position, + var between = Vector2.Distance(npc.Center, player.Center); + var inRange = between < 650; + + var lineOfSight = Collision.CanHitLine(player.position, player.width, player.height, npc.position, npc.width, npc.height); - - if (inRange && lineOfSight) { - Vector2 tpPos = npc.position; - tpPos.X += -(npc.direction * npc.width + (player.width*2)); - - if (Collision.TileCollision(tpPos, Vector2.Zero, player.width, player.height) != Vector2.Zero) return true; - - player.Teleport(tpPos, TeleportationStyleID.RodOfDiscord); - player.velocity = Vector2.Zero; - player.NinjaDodge(); - return true; - } + + if (!inRange || !lineOfSight) continue; + var tpPos = npc.position; + tpPos.X += -(npc.direction * npc.width + (player.width * 2)); + + if (Collision.TileCollision(tpPos, Vector2.Zero, player.width, player.height) != Vector2.Zero) return true; + + player.Teleport(tpPos, TeleportationStyleID.RodOfDiscord); + player.velocity = Vector2.Zero; + player.NinjaDodge(); + return true; } - + return null; } -} +} \ No newline at end of file diff --git a/Items/MithrilPebbleOfPigSmiting.cs b/Items/MithrilPebbleOfPigSmiting.cs index 37b365e..878b9ae 100644 --- a/Items/MithrilPebbleOfPigSmiting.cs +++ b/Items/MithrilPebbleOfPigSmiting.cs @@ -7,20 +7,6 @@ namespace YHTMod.Items; public class MithrilPebbleOfPigSmiting : ModItem { public override void SetStaticDefaults() { - DisplayName.SetDefault("Mithril Pebble of Pig Smiting"); - Tooltip.SetDefault( - "For you see long ago this pebble was forged in the fiery pits of Tartarus. By the grand blacksmith of Lucifer himself. In a time before the world began there were\n" + - "pigs that roamed the world of aincrad. They took what they pleased and did what they wanted. The humans tried to survive but the pigs were too powerful. Then a man stood against the hogs!\n" + - "His name... Well its not a Him its a Her...HER name...was...Akane! Lucifer crafted this mighty weapon for Akane. Amd she threw it Over and Over, Again and Again. She freed\n" + - "the humans but the pigs wouldn't give up! In a mighty battle Akane fell to the Hogs Hero, Becon! Like Bacon but with a 'E' instead of a 'A'. ANYWAY Becon used his Cleaver to strike\n" + - "down Akane. And the pebble fell. One of the hogs tried to pick it up but that hog died as soon as he touched the stone. Another Hero picked up the pebble. It was Akanes Apprentice. Sophie.\n" + - "The hogs ran from the battlefield as Sophie threw the pebble. Striking many of them down. But there were too many. After returning home Sophie trained hard and set off to find Becon.\n" + - "She killed hog after hog looking for him. One little piggy spilled and told her when he was. She made Becon, Into Bacon. Battle after battle the Hogs Became weaker. With time so did Sophie.\n" + - "She died because she ate too much Pork. And the Pebble was passed too Marjosa. He made a decision. Instead of killing them all. He made them walk on four legs. He would eat them and keep them\n" + - "locked up where they cant escape. Some Hogs rebelled but most of them went with it. Accepting defeat. Then as Marjosa was Hunting wild Hogs. 3 appeared at once. Taking him by surprise.\n" + - "They hit him with there sharp horns. Marjosa hit the with the Mighty Pebble killing them all but he was weak and far from anyone who could offer help. And Thus, Marjosa\n" + - "Guardian of the Pebble fell to his knees and passed from this world. Leaving behind the mighty weapon. For he knew. One day its power would be required once more.\n" + - "But the Legacy of the pebble lives on."); CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1; } diff --git a/Items/ToclafaneStaff.cs b/Items/ToclafaneStaff.cs index b2e1ae2..f77cee5 100644 --- a/Items/ToclafaneStaff.cs +++ b/Items/ToclafaneStaff.cs @@ -12,8 +12,6 @@ namespace YHTMod.Items; public class ToclafaneStaff : ModItem { public override void SetStaticDefaults() { - DisplayName.SetDefault("Toclafane Staff"); - Tooltip.SetDefault("Summons a toclafane to remove population for you"); ItemID.Sets.GamepadWholeScreenUseRange[Item.type] = true; // This lets the player target anywhere on the whole screen while using a controller. ItemID.Sets.LockOnIgnoresCollision[Item.type] = true; CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1; diff --git a/Localization/en-US_Mods.YHTMod.hjson b/Localization/en-US_Mods.YHTMod.hjson new file mode 100644 index 0000000..31ea67f --- /dev/null +++ b/Localization/en-US_Mods.YHTMod.hjson @@ -0,0 +1,56 @@ +Buffs: { + ToclafaneMinionBuff: { + DisplayName: "Summon Toclafane" + Description: "It came from a parallel world to fight for its Master." + } +} + +Items: { + ArcaneMissile: { + DisplayName: Arcane Missile + Tooltip: ''' + Magical projectile crits shoot a homing arcane missile + Arcane missiles cannot crit + ''' + } + + CopperSwordOnAStick: { + DisplayName: Copper Sword On A Stick + Tooltip: "" + } + + MithrilPebbleOfPigSmiting: { + DisplayName: Mithril Pebble Of Pig Smiting + Tooltip: ''' + For you see long ago this pebble was forged in the fiery pits of Tartarus. By the grand blacksmith of Lucifer himself. + In a time before the world began there were pigs that roamed the world of Aincrad. They took what they pleased and did + what they wanted. The humans tried to survive but the pigs were too powerful. Then a man stood against the hogs! His + name... Well its not a Him its a Her...HER name...was...Akane! Lucifer crafted this mighty weapon for Akane. And she + threw it Over and Over, Again and Again. She freed the humans but the pigs wouldn't give up! In a mighty battle Akane + fell to the Hogs Hero, Becon! Like Bacon but with a 'E' instead of a 'A'. ANYWAY Becon used his Cleaver to strike down + Akane. And the pebble fell. One of the hogs tried to pick it up but that hog died as soon as he touched the stone. + Another Hero picked up the pebble. It was Akane's Apprentice. Sophie. The hogs ran from the battlefield as Sophie threw + the pebble. Striking many of them down. But there were too many. After returning home Sophie trained hard and set off + to find Becon. She killed hog after hog looking for him. One little piggy spilled and told her when he was. She made + Becon, Into Bacon. Battle after battle the Hogs Became weaker. With time so did Sophie. She died because she ate too + much Pork. And the Pebble was passed too Marjosa. He made a decision. Instead of killing them all. He made them walk + on four legs. He would eat them and keep them locked up where they cant escape. Some Hogs rebelled but most of them + went with it. Accepting defeat. Then as Marjosa was Hunting wild Hogs. 3 appeared at once. Taking him by surprise. + They hit him with there sharp horns. Marjosa hit the with the Mighty Pebble killing them all but he was weak and far + from anyone who could offer help. And Thus, Marjosa Guardian of the Pebble fell to his knees and passed from this + world. Leaving behind the mighty weapon. For he knew. One day its power would be required once more. + But the Legacy of the pebble lives on. + ''' + } + + ToclafaneStaff: { + DisplayName: Toclafane Staff + Tooltip: "Summons a toclafane to remove population for you" + } +} + +Projectiles: { + CopperSwordOnAStickProjectile.DisplayName: Copper Sword On A Stick + MithrilPebbleOfPigSmitingProjectile.DisplayName: Mithril Pebble Of Pig Smiting + ToclafaneMinion.DisplayName: Toclafane Minion +} diff --git a/Projectiles/Weapons/MithrilPebbleOfPigSmitingProjectile.cs b/Projectiles/Weapons/MithrilPebbleOfPigSmitingProjectile.cs index 44f163e..be33921 100644 --- a/Projectiles/Weapons/MithrilPebbleOfPigSmitingProjectile.cs +++ b/Projectiles/Weapons/MithrilPebbleOfPigSmitingProjectile.cs @@ -24,7 +24,7 @@ class MithrilPebbleOfPigSmitingProjectile : ModProjectile { base.AI(); DrawOriginOffsetX = 0; DrawOffsetX = 0; - int dust = Dust.NewDust(Projectile.Center, 1, 1, DustID.Mythril, 0f, 0f, 0, default(Color), 1f); + var dust = Dust.NewDust(Projectile.Center, 1, 1, DustID.Mythril, 0f, 0f, 0, default(Color), 1f); Main.dust[dust].noGravity = true; Main.dust[dust].velocity *= 0.3f; } diff --git a/Projectiles/Weapons/ToclafaneMinion.cs b/Projectiles/Weapons/ToclafaneMinion.cs index c04c310..69c9a9a 100644 --- a/Projectiles/Weapons/ToclafaneMinion.cs +++ b/Projectiles/Weapons/ToclafaneMinion.cs @@ -7,13 +7,13 @@ using YHTMod.Buffs; namespace YHTMod.Projectiles.Weapons; -public class ToclafaneMinion : ModProjectile { +public class ToclafaneMinion : ModProjectile +{ + private int _shootCooldown = 0; + private AttackMode _attackMode = AttackMode.Ranged; - private int shootCooldown = 0; - private AttackMode attackMode = AttackMode.RANGED; - - public override void SetStaticDefaults() { - DisplayName.SetDefault("Toclafane Minion"); + public override void SetStaticDefaults() + { // Sets the amount of frames this minion has on its spritesheet Main.projFrames[Projectile.type] = 8; // This is necessary for right-click targeting @@ -23,7 +23,8 @@ public class ToclafaneMinion : ModProjectile { ProjectileID.Sets.MinionSacrificable[Projectile.type] = true; } - public sealed override void SetDefaults() { + public sealed override void SetDefaults() + { Projectile.width = 32; Projectile.height = 32; Projectile.scale = 0.65f; @@ -36,24 +37,29 @@ public class ToclafaneMinion : ModProjectile { Projectile.penetrate = -1; } - public override bool? CanCutTiles() { + public override bool? CanCutTiles() + { return false; } - public override bool MinionContactDamage() { + public override bool MinionContactDamage() + { return true; } - public override void AI() { - Player player = Main.player[Projectile.owner]; + public override void AI() + { + var player = Main.player[Projectile.owner]; #region Active check - if (player.dead || !player.active) { + if (player.dead || !player.active) + { player.ClearBuff(ModContent.BuffType()); } - if (player.HasBuff(ModContent.BuffType())) { + if (player.HasBuff(ModContent.BuffType())) + { Projectile.timeLeft = 2; } @@ -61,13 +67,14 @@ public class ToclafaneMinion : ModProjectile { #region General behavior - if (shootCooldown > 0) { - shootCooldown = shootCooldown - 1; + if (_shootCooldown > 0) + { + _shootCooldown = _shootCooldown - 1; } - attackMode = AttackMode.RANGED; + _attackMode = AttackMode.Ranged; - Vector2 idlePosition = player.Center; + var idlePosition = player.Center; idlePosition.Y -= 48f; float minionPositionOffsetX = (10 + Projectile.minionPos * 40) * -player.direction; @@ -76,9 +83,10 @@ public class ToclafaneMinion : ModProjectile { // All of this code below this line is adapted from Spazmamini code (ID 388, aiStyle 66) // Teleport to player if distance is too big - Vector2 vectorToIdlePosition = idlePosition - Projectile.Center; - float distanceToIdlePosition = vectorToIdlePosition.Length(); - if (Main.myPlayer == player.whoAmI && distanceToIdlePosition > 2000f) { + var vectorToIdlePosition = idlePosition - Projectile.Center; + var distanceToIdlePosition = vectorToIdlePosition.Length(); + if (Main.myPlayer == player.whoAmI && distanceToIdlePosition > 2000f) + { // Whenever you deal with non-regular events that change the behavior or position drastically, make sure to only run the code on the owner of the projectile, // and then set netUpdate to true Projectile.position = idlePosition; @@ -87,18 +95,18 @@ public class ToclafaneMinion : ModProjectile { } // If your minion is flying, you want to do this independently of any conditions - float overlapVelocity = 0.04f; - for (int i = 0; i < Main.maxProjectiles; i++) { + const float overlapVelocity = 0.04f; + for (var i = 0; i < Main.maxProjectiles; i++) + { // Fix overlap with other minions - Projectile other = Main.projectile[i]; - if (i != Projectile.whoAmI && other.active && other.owner == Projectile.owner && - Math.Abs(Projectile.position.X - other.position.X) + - Math.Abs(Projectile.position.Y - other.position.Y) < Projectile.width) { - if (Projectile.position.X < other.position.X) Projectile.velocity.X -= overlapVelocity; - else Projectile.velocity.X += overlapVelocity; - if (Projectile.position.Y < other.position.Y) Projectile.velocity.Y -= overlapVelocity; - else Projectile.velocity.Y += overlapVelocity; - } + var other = Main.projectile[i]; + if (i == Projectile.whoAmI || !other.active || other.owner != Projectile.owner || + !(Math.Abs(Projectile.position.X - other.position.X) + + Math.Abs(Projectile.position.Y - other.position.Y) < Projectile.width)) continue; + if (Projectile.position.X < other.position.X) Projectile.velocity.X -= overlapVelocity; + else Projectile.velocity.X += overlapVelocity; + if (Projectile.position.Y < other.position.Y) Projectile.velocity.Y -= overlapVelocity; + else Projectile.velocity.Y += overlapVelocity; } #endregion @@ -106,40 +114,42 @@ public class ToclafaneMinion : ModProjectile { #region Find target // Starting search distance - float distanceFromTarget = 700f; - Vector2 targetCenter = Projectile.position; - bool foundTarget = false; + var distanceFromTarget = 700f; + var targetCenter = Projectile.position; + var foundTarget = false; // This code is required if your minion weapon has the targeting feature - if (player.HasMinionAttackTargetNPC) { - NPC npc = Main.npc[player.MinionAttackTargetNPC]; - float between = Vector2.Distance(npc.Center, Projectile.Center); + if (player.HasMinionAttackTargetNPC) + { + var npc = Main.npc[player.MinionAttackTargetNPC]; + var between = Vector2.Distance(npc.Center, Projectile.Center); // Reasonable distance away so it doesn't target across multiple screens - if (between < 2000f) { + if (between < 2000f) + { distanceFromTarget = between; targetCenter = npc.Center; foundTarget = true; } } - if (!foundTarget) { - for (int i = 0; i < Main.maxNPCs; i++) { - NPC npc = Main.npc[i]; - if (npc.CanBeChasedBy()) { - float between = Vector2.Distance(npc.Center, Projectile.Center); - bool closest = Vector2.Distance(Projectile.Center, targetCenter) > between; - bool inRange = between < distanceFromTarget; - bool lineOfSight = Collision.CanHitLine(Projectile.position, Projectile.width, - Projectile.height, npc.position, npc.width, npc.height); - // Additional check for this specific minion behavior, otherwise it will stop attacking once it dashed through an enemy while flying though tiles afterwards - // The number depends on various parameters seen in the movement code below. Test different ones out until it works alright - bool closeThroughWall = between < 100f; - if (((closest && inRange) || !foundTarget) && (lineOfSight || closeThroughWall)) { - distanceFromTarget = between; - targetCenter = npc.Center; - foundTarget = true; - } - } + if (!foundTarget) + { + for (var i = 0; i < Main.maxNPCs; i++) + { + var npc = Main.npc[i]; + if (!npc.CanBeChasedBy()) continue; + var between = Vector2.Distance(npc.Center, Projectile.Center); + var closest = Vector2.Distance(Projectile.Center, targetCenter) > between; + var inRange = between < distanceFromTarget; + var lineOfSight = Collision.CanHitLine(Projectile.position, Projectile.width, + Projectile.height, npc.position, npc.width, npc.height); + // Additional check for this specific minion behavior, otherwise it will stop attacking once it dashed through an enemy while flying though tiles afterwards + // The number depends on various parameters seen in the movement code below. Test different ones out until it works alright + var closeThroughWall = between < 100f; + if (((!closest || !inRange) && foundTarget) || (!lineOfSight && !closeThroughWall)) continue; + distanceFromTarget = between; + targetCenter = npc.Center; + foundTarget = true; } } @@ -150,46 +160,56 @@ public class ToclafaneMinion : ModProjectile { #region Movement // Default movement parameters (here for attacking) - float speed = 8f; - float inertia = 20f; + var speed = 8f; + var inertia = 20f; - if (foundTarget) { - Vector2 direction = targetCenter - Projectile.Center; + if (foundTarget) + { + var direction = targetCenter - Projectile.Center; direction.Normalize(); - if (distanceFromTarget > 40f) { + if (distanceFromTarget > 40f) + { // The immediate range around the target (so it doesn't latch onto it when close) direction *= speed; Projectile.velocity = (Projectile.velocity * (inertia - 1) + direction) / inertia; } - if (distanceFromTarget <= 120f) { - attackMode = AttackMode.MELEE; - } - - if (distanceFromTarget > 120f && shootCooldown == 0) { - shootCooldown = 60; // 1 second between shots - Projectile laser = Projectile.NewProjectileDirect(player.GetSource_FromThis(), Projectile.Center, - direction, ProjectileID.DeathLaser, 30, Projectile.knockBack, Projectile.owner); - laser.friendly = true; - laser.hostile = false; - laser.penetrate = 5; - attackMode = AttackMode.RANGED; + switch (distanceFromTarget) + { + case <= 120f: + _attackMode = AttackMode.Melee; + break; + case > 120f when _shootCooldown == 0: + { + _shootCooldown = 60; // 1 second between shots + var laser = Projectile.NewProjectileDirect(player.GetSource_FromThis(), Projectile.Center, + direction, ProjectileID.DeathLaser, 30, Projectile.knockBack, Projectile.owner); + laser.friendly = true; + laser.hostile = false; + laser.penetrate = 5; + _attackMode = AttackMode.Ranged; + break; + } } } - else { + else + { // Minion doesn't have a target: return to player and idle - if (distanceToIdlePosition > 600f) { + if (distanceToIdlePosition > 600f) + { // Speed up the minion if it's away from the player speed = 12f; inertia = 60f; } - else { + else + { // Slow down the minion if closer to the player speed = 4f; inertia = 80f; } - if (distanceToIdlePosition > 20f) { + if (distanceToIdlePosition > 20f) + { // The immediate range around the player (when it passively floats about) // This is a simple movement formula using the two parameters and its desired direction to create a "homing" movement @@ -197,7 +217,8 @@ public class ToclafaneMinion : ModProjectile { vectorToIdlePosition *= speed; Projectile.velocity = (Projectile.velocity * (inertia - 1) + vectorToIdlePosition) / inertia; } - else if (Projectile.velocity == Vector2.Zero) { + else if (Projectile.velocity == Vector2.Zero) + { // If there is a case where it's not moving at all, give it a little "poke" Projectile.velocity.X = -0.15f; Projectile.velocity.Y = -0.05f; @@ -211,66 +232,67 @@ public class ToclafaneMinion : ModProjectile { // So it will lean slightly towards the direction it's moving Projectile.rotation = Projectile.velocity.X * 0.05f; - int frameSpeed = 8; + const int frameSpeed = 8; Projectile.frameCounter++; - if (Projectile.frameCounter >= frameSpeed) { + if (Projectile.frameCounter >= frameSpeed) + { Projectile.frameCounter = 0; - if (attackMode == AttackMode.MELEE) { - switch (Projectile.frame) { - case 0: - Projectile.frame++; - break; - case 1: - Projectile.frame++; - break; - case 2: - Projectile.frame++; - break; - case 3: - Projectile.frame = 0; - break; - case 4: - Projectile.frame = 1; - break; - case 5: - Projectile.frame = 2; - break; - case 6: - Projectile.frame = 3; - break; - case 7: - Projectile.frame = 4; - break; - } - } + switch (_attackMode) + { + case AttackMode.Melee: + switch (Projectile.frame) + { + case 0: + case 1: + case 2: + Projectile.frame++; + break; + case 3: + Projectile.frame = 0; + break; + case 4: + Projectile.frame = 1; + break; + case 5: + Projectile.frame = 2; + break; + case 6: + Projectile.frame = 3; + break; + case 7: + Projectile.frame = 4; + break; + } - if (attackMode == AttackMode.RANGED) { - switch (Projectile.frame) { - case 0: - Projectile.frame = 5; - break; - case 1: - Projectile.frame = 6; - break; - case 2: - Projectile.frame = 7; - break; - case 3: - Projectile.frame = 4; - break; - case 4: - Projectile.frame++; - break; - case 5: - Projectile.frame++; - break; - case 6: - Projectile.frame++; - break; - case 7: - Projectile.frame = 4; - break; - } + break; + case AttackMode.Ranged: + switch (Projectile.frame) + { + case 0: + Projectile.frame = 5; + break; + case 1: + Projectile.frame = 6; + break; + case 2: + Projectile.frame = 7; + break; + case 3: + Projectile.frame = 4; + break; + case 4: + case 5: + case 6: + Projectile.frame++; + break; + case 7: + Projectile.frame = 4; + break; + } + + break; + default: + break; } } @@ -279,8 +301,9 @@ public class ToclafaneMinion : ModProjectile { #endregion } - enum AttackMode { - MELEE, - RANGED + private enum AttackMode + { + Melee, + Ranged, } -} +} \ No newline at end of file