2 Commits

19 changed files with 265 additions and 398 deletions
+8 -11
View File
@@ -4,22 +4,19 @@ using YHTMod.Projectiles.Weapons;
namespace YHTMod.Buffs; namespace YHTMod.Buffs;
public class ToclafaneMinionBuff : ModBuff public class ToclafaneMinionBuff : ModBuff {
{
public override void SetStaticDefaults() public override void SetStaticDefaults() {
{ DisplayName.SetDefault("Summon Toclafane");
Description.SetDefault("It came from a parallel world to fight for its Master.");
Main.buffNoSave[Type] = true; Main.buffNoSave[Type] = true;
Main.buffNoTimeDisplay[Type] = true; Main.buffNoTimeDisplay[Type] = true;
} }
public override void Update(Player player, ref int buffIndex) public override void Update(Player player, ref int buffIndex) {
{ if (player.ownedProjectileCounts[ModContent.ProjectileType<ToclafaneMinion>()] > 0) {
if (player.ownedProjectileCounts[ModContent.ProjectileType<ToclafaneMinion>()] > 0)
{
player.buffTime[buffIndex] = 18000; player.buffTime[buffIndex] = 18000;
} } else {
else
{
player.DelBuff(buffIndex); player.DelBuff(buffIndex);
buffIndex--; buffIndex--;
} }
+5 -18
View File
@@ -1,32 +1,19 @@
using Terraria; using Terraria;
using Terraria.GameContent.ItemDropRules; using Terraria.GameContent.ItemDropRules;
using Terraria.ID; using Terraria.ID;
using Terraria.ModLoader; using Terraria.ModLoader;
using YHTMod.Items; using YHTMod.Items;
using YHTMod.Items.ArcaneMissile;
namespace YHTMod.Changes; namespace YHTMod.Changes;
public class NpcLoot : GlobalNPC public class NpcLoot : GlobalNPC
{ {
public override void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) public override void ModifyNPCLoot(NPC npc, NPCLoot npcLoot) {
{ int id = npc.type;
var id = npc.type; if (NPCID.Sets.CountsAsCritter[id]) {
npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<MithrilPebbleOfPigSmiting>(), 400, 1, 1));
if (NPCID.Sets.CountsAsCritter[id])
{
npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<MithrilPebbleOfPigSmiting>(), 400));
}
switch (id)
{
case NPCID.Plantera:
npcLoot.Add(ItemDropRule.Common(ItemID.ChlorophyteOre, 1, 60, 80));
break;
case NPCID.Tim:
npcLoot.Add(ItemDropRule.Common(ModContent.ItemType<ArcaneMissile>()));
break;
} }
} }
} }
+47
View File
@@ -0,0 +1,47 @@
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.Chat;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using YHTMod.Items;
namespace YHTMod.Changes;
public class TheKeyBehavior : GlobalTile {
public override void RightClick(int i, int j, int type) {
if (type != TileID.Containers) {
base.RightClick(i, j, type);
return;
}
bool foundKey = false;
foreach (Item item in Main.LocalPlayer.inventory) {
if (item.type.Equals(ModContent.ItemType<TheKey>())) {
foundKey = true;
break;
}
}
ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral(foundKey.ToString()), Color.White);
if (!foundKey) {
return;
}
ChatHelper.BroadcastChatMessage(NetworkText.FromLiteral("Found key!"), Color.White);
if (!Chest.IsLocked(i, j)) {
base.RightClick(i, j, type);
return;
}
Chest.Unlock(i, j);
if (Main.netMode == NetmodeID.MultiplayerClient)
NetMessage.SendData(MessageID.Unlock, number: 1, number2: 1f, number3: i, number4: j);
}
}
-33
View File
@@ -1,33 +0,0 @@
using Terraria;
using Terraria.GameContent.Creative;
using Terraria.ID;
using Terraria.ModLoader;
namespace YHTMod.Items.ArcaneMissile;
public class ArcaneMissile : ModItem
{
public override void SetStaticDefaults()
{
CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;
}
public override void SetDefaults()
{
Item.width = 64;
Item.height = 64;
Item.accessory = true;
Item.damage = 10;
Item.rare = ItemRarityID.LightRed;
Item.DamageType = DamageClass.Magic;
Item.noMelee = true;
Item.noUseGraphic = true;
}
public override void UpdateAccessory(Player player, bool hideVisual)
{
player.GetModPlayer<YhtPlayer>().arcaneMissle = Item.damage;
base.UpdateAccessory(player, hideVisual);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

@@ -1,50 +0,0 @@
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace YHTMod.Items.ArcaneMissile;
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)
{
return;
}
var player = Main.LocalPlayer;
if (player.GetModPlayer<YhtPlayer>().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,
player.GetModPlayer<YhtPlayer>().arcaneMissle,
0,
Main.LocalPlayer.whoAmI
);
proj.friendly = true;
proj.hostile = false;
proj.timeLeft = 300;
proj.maxPenetrate = 1;
proj.tileCollide = false;
proj.DamageType = DamageClass.Magic;
proj.aiStyle = ProjAIStyleID.MagicMissile;
// Prevent crits for the missiles
proj.CritChance = int.MinValue;
}
base.OnHitByProjectile(npc, projectile, hitInfo, damage);
}
}
+1
View File
@@ -7,6 +7,7 @@ namespace YHTMod.Items;
public class CopperSwordOnAStick : ModItem { public class CopperSwordOnAStick : ModItem {
public override void SetStaticDefaults() { public override void SetStaticDefaults() {
DisplayName.SetDefault("Copper Sword On A Stick");
CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1; CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;
} }
+24 -28
View File
@@ -6,49 +6,45 @@ using Terraria.ModLoader;
namespace YHTMod.Items; namespace YHTMod.Items;
public class KatanaRedo : GlobalItem public class KatanaRedo : GlobalItem {
{
public override void ModifyTooltips(Item item, List<TooltipLine> tooltips) public override void ModifyTooltips(Item item, List<TooltipLine> tooltips)
{ {
if (item.type != ItemID.Katana) return; if (item.type != ItemID.Katana) return;
tooltips.Insert(5, new TooltipLine(YHTMod.GetInstance(), "flavor", "Nothing personel kid.")); 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(6, new TooltipLine(YHTMod.GetInstance(), "usage" , "Right click to teleport behind them."));
} }
public override bool AltFunctionUse(Item item, Player player) public override bool AltFunctionUse(Item item, Player player) {
{ if (item.type != ItemID.Katana) {
return item.type == ItemID.Katana || base.AltFunctionUse(item, player); return base.AltFunctionUse(item, player);
}
return true;
} }
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; if (item.type != ItemID.Katana || player.altFunctionUse != 2) return null;
var yhtPlayer = player.GetModPlayer<YhtPlayer>(); for (int i = 0; i < Main.maxNPCs; i++) {
NPC npc = Main.npc[i];
if (yhtPlayer.katanaTeleportCooldown > 0) return null;
yhtPlayer.katanaTeleportCooldown = 300;
for (var i = 0; i < Main.maxNPCs; i++)
{
var npc = Main.npc[i];
if (!npc.CanBeChasedBy()) continue; if (!npc.CanBeChasedBy()) continue;
var between = Vector2.Distance(npc.Center, player.Center); float between = Vector2.Distance(npc.Center, player.Center);
var inRange = between < 650; bool inRange = between < 650;
var lineOfSight = Collision.CanHitLine(player.position, player.width, player.height, npc.position, bool lineOfSight = Collision.CanHitLine(player.position, player.width, player.height, npc.position,
npc.width, npc.height); npc.width, npc.height);
if (!inRange || !lineOfSight) continue; if (inRange && lineOfSight) {
var tpPos = npc.position; Vector2 tpPos = npc.position;
tpPos.X += -(npc.direction * npc.width + (player.width * 2)); tpPos.X += -(npc.direction * npc.width + (player.width*2));
if (Collision.TileCollision(tpPos, Vector2.Zero, player.width, player.height) != Vector2.Zero) return true; if (Collision.TileCollision(tpPos, Vector2.Zero, player.width, player.height) != Vector2.Zero) return true;
player.Teleport(tpPos, TeleportationStyleID.RodOfDiscord); player.Teleport(tpPos, TeleportationStyleID.RodOfDiscord);
player.velocity = Vector2.Zero; player.velocity = Vector2.Zero;
player.NinjaDodge(); player.NinjaDodge();
return true; return true;
}
} }
return null; return null;
+14
View File
@@ -7,6 +7,20 @@ namespace YHTMod.Items;
public class MithrilPebbleOfPigSmiting : ModItem { public class MithrilPebbleOfPigSmiting : ModItem {
public override void SetStaticDefaults() { 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; CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;
} }
+14
View File
@@ -0,0 +1,14 @@
using Terraria.GameContent.Creative;
using Terraria.ModLoader;
namespace YHTMod.Items;
public class TheKey : ModItem {
public override void SetStaticDefaults() {
DisplayName.SetDefault("The Key");
Tooltip.SetDefault("Opens all locks.");
CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

+2
View File
@@ -12,6 +12,8 @@ namespace YHTMod.Items;
public class ToclafaneStaff : ModItem { public class ToclafaneStaff : ModItem {
public override void SetStaticDefaults() { 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.GamepadWholeScreenUseRange[Item.type] = true; // This lets the player target anywhere on the whole screen while using a controller.
ItemID.Sets.LockOnIgnoresCollision[Item.type] = true; ItemID.Sets.LockOnIgnoresCollision[Item.type] = true;
CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1; CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;
-58
View File
@@ -1,58 +0,0 @@
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
}
@@ -24,7 +24,7 @@ class MithrilPebbleOfPigSmitingProjectile : ModProjectile {
base.AI(); base.AI();
DrawOriginOffsetX = 0; DrawOriginOffsetX = 0;
DrawOffsetX = 0; DrawOffsetX = 0;
var dust = Dust.NewDust(Projectile.Center, 1, 1, DustID.Mythril, 0f, 0f, 0, default(Color), 1f); int dust = Dust.NewDust(Projectile.Center, 1, 1, DustID.Mythril, 0f, 0f, 0, default(Color), 1f);
Main.dust[dust].noGravity = true; Main.dust[dust].noGravity = true;
Main.dust[dust].velocity *= 0.3f; Main.dust[dust].velocity *= 0.3f;
} }
+138 -161
View File
@@ -7,13 +7,13 @@ using YHTMod.Buffs;
namespace YHTMod.Projectiles.Weapons; namespace YHTMod.Projectiles.Weapons;
public class ToclafaneMinion : ModProjectile public class ToclafaneMinion : ModProjectile {
{
private int _shootCooldown = 0;
private AttackMode _attackMode = AttackMode.Ranged;
public override void SetStaticDefaults() private int shootCooldown = 0;
{ private AttackMode attackMode = AttackMode.RANGED;
public override void SetStaticDefaults() {
DisplayName.SetDefault("Toclafane Minion");
// Sets the amount of frames this minion has on its spritesheet // Sets the amount of frames this minion has on its spritesheet
Main.projFrames[Projectile.type] = 8; Main.projFrames[Projectile.type] = 8;
// This is necessary for right-click targeting // This is necessary for right-click targeting
@@ -23,8 +23,7 @@ public class ToclafaneMinion : ModProjectile
ProjectileID.Sets.MinionSacrificable[Projectile.type] = true; ProjectileID.Sets.MinionSacrificable[Projectile.type] = true;
} }
public sealed override void SetDefaults() public sealed override void SetDefaults() {
{
Projectile.width = 32; Projectile.width = 32;
Projectile.height = 32; Projectile.height = 32;
Projectile.scale = 0.65f; Projectile.scale = 0.65f;
@@ -37,29 +36,24 @@ public class ToclafaneMinion : ModProjectile
Projectile.penetrate = -1; Projectile.penetrate = -1;
} }
public override bool? CanCutTiles() public override bool? CanCutTiles() {
{
return false; return false;
} }
public override bool MinionContactDamage() public override bool MinionContactDamage() {
{
return true; return true;
} }
public override void AI() public override void AI() {
{ Player player = Main.player[Projectile.owner];
var player = Main.player[Projectile.owner];
#region Active check #region Active check
if (player.dead || !player.active) if (player.dead || !player.active) {
{
player.ClearBuff(ModContent.BuffType<ToclafaneMinionBuff>()); player.ClearBuff(ModContent.BuffType<ToclafaneMinionBuff>());
} }
if (player.HasBuff(ModContent.BuffType<ToclafaneMinionBuff>())) if (player.HasBuff(ModContent.BuffType<ToclafaneMinionBuff>())) {
{
Projectile.timeLeft = 2; Projectile.timeLeft = 2;
} }
@@ -67,14 +61,13 @@ public class ToclafaneMinion : ModProjectile
#region General behavior #region General behavior
if (_shootCooldown > 0) if (shootCooldown > 0) {
{ shootCooldown = shootCooldown - 1;
_shootCooldown = _shootCooldown - 1;
} }
_attackMode = AttackMode.Ranged; attackMode = AttackMode.RANGED;
var idlePosition = player.Center; Vector2 idlePosition = player.Center;
idlePosition.Y -= 48f; idlePosition.Y -= 48f;
float minionPositionOffsetX = (10 + Projectile.minionPos * 40) * -player.direction; float minionPositionOffsetX = (10 + Projectile.minionPos * 40) * -player.direction;
@@ -83,10 +76,9 @@ public class ToclafaneMinion : ModProjectile
// All of this code below this line is adapted from Spazmamini code (ID 388, aiStyle 66) // All of this code below this line is adapted from Spazmamini code (ID 388, aiStyle 66)
// Teleport to player if distance is too big // Teleport to player if distance is too big
var vectorToIdlePosition = idlePosition - Projectile.Center; Vector2 vectorToIdlePosition = idlePosition - Projectile.Center;
var distanceToIdlePosition = vectorToIdlePosition.Length(); float distanceToIdlePosition = vectorToIdlePosition.Length();
if (Main.myPlayer == player.whoAmI && distanceToIdlePosition > 2000f) 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, // 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 // and then set netUpdate to true
Projectile.position = idlePosition; Projectile.position = idlePosition;
@@ -95,18 +87,18 @@ public class ToclafaneMinion : ModProjectile
} }
// If your minion is flying, you want to do this independently of any conditions // If your minion is flying, you want to do this independently of any conditions
const float overlapVelocity = 0.04f; float overlapVelocity = 0.04f;
for (var i = 0; i < Main.maxProjectiles; i++) for (int i = 0; i < Main.maxProjectiles; i++) {
{
// Fix overlap with other minions // Fix overlap with other minions
var other = Main.projectile[i]; Projectile other = Main.projectile[i];
if (i == Projectile.whoAmI || !other.active || other.owner != Projectile.owner || if (i != Projectile.whoAmI && other.active && other.owner == Projectile.owner &&
!(Math.Abs(Projectile.position.X - other.position.X) + Math.Abs(Projectile.position.X - other.position.X) +
Math.Abs(Projectile.position.Y - other.position.Y) < Projectile.width)) continue; Math.Abs(Projectile.position.Y - other.position.Y) < Projectile.width) {
if (Projectile.position.X < other.position.X) Projectile.velocity.X -= overlapVelocity; if (Projectile.position.X < other.position.X) Projectile.velocity.X -= overlapVelocity;
else Projectile.velocity.X += overlapVelocity; else Projectile.velocity.X += overlapVelocity;
if (Projectile.position.Y < other.position.Y) Projectile.velocity.Y -= overlapVelocity; if (Projectile.position.Y < other.position.Y) Projectile.velocity.Y -= overlapVelocity;
else Projectile.velocity.Y += overlapVelocity; else Projectile.velocity.Y += overlapVelocity;
}
} }
#endregion #endregion
@@ -114,42 +106,40 @@ public class ToclafaneMinion : ModProjectile
#region Find target #region Find target
// Starting search distance // Starting search distance
var distanceFromTarget = 700f; float distanceFromTarget = 700f;
var targetCenter = Projectile.position; Vector2 targetCenter = Projectile.position;
var foundTarget = false; bool foundTarget = false;
// This code is required if your minion weapon has the targeting feature // This code is required if your minion weapon has the targeting feature
if (player.HasMinionAttackTargetNPC) if (player.HasMinionAttackTargetNPC) {
{ NPC npc = Main.npc[player.MinionAttackTargetNPC];
var npc = Main.npc[player.MinionAttackTargetNPC]; float between = Vector2.Distance(npc.Center, Projectile.Center);
var between = Vector2.Distance(npc.Center, Projectile.Center);
// Reasonable distance away so it doesn't target across multiple screens // Reasonable distance away so it doesn't target across multiple screens
if (between < 2000f) if (between < 2000f) {
{
distanceFromTarget = between; distanceFromTarget = between;
targetCenter = npc.Center; targetCenter = npc.Center;
foundTarget = true; foundTarget = true;
} }
} }
if (!foundTarget) if (!foundTarget) {
{ for (int i = 0; i < Main.maxNPCs; i++) {
for (var i = 0; i < Main.maxNPCs; i++) NPC npc = Main.npc[i];
{ if (npc.CanBeChasedBy()) {
var npc = Main.npc[i]; float between = Vector2.Distance(npc.Center, Projectile.Center);
if (!npc.CanBeChasedBy()) continue; bool closest = Vector2.Distance(Projectile.Center, targetCenter) > between;
var between = Vector2.Distance(npc.Center, Projectile.Center); bool inRange = between < distanceFromTarget;
var closest = Vector2.Distance(Projectile.Center, targetCenter) > between; bool lineOfSight = Collision.CanHitLine(Projectile.position, Projectile.width,
var inRange = between < distanceFromTarget; Projectile.height, npc.position, npc.width, npc.height);
var lineOfSight = Collision.CanHitLine(Projectile.position, Projectile.width, // Additional check for this specific minion behavior, otherwise it will stop attacking once it dashed through an enemy while flying though tiles afterwards
Projectile.height, npc.position, npc.width, npc.height); // The number depends on various parameters seen in the movement code below. Test different ones out until it works alright
// Additional check for this specific minion behavior, otherwise it will stop attacking once it dashed through an enemy while flying though tiles afterwards bool closeThroughWall = between < 100f;
// The number depends on various parameters seen in the movement code below. Test different ones out until it works alright if (((closest && inRange) || !foundTarget) && (lineOfSight || closeThroughWall)) {
var closeThroughWall = between < 100f; distanceFromTarget = between;
if (((!closest || !inRange) && foundTarget) || (!lineOfSight && !closeThroughWall)) continue; targetCenter = npc.Center;
distanceFromTarget = between; foundTarget = true;
targetCenter = npc.Center; }
foundTarget = true; }
} }
} }
@@ -160,56 +150,46 @@ public class ToclafaneMinion : ModProjectile
#region Movement #region Movement
// Default movement parameters (here for attacking) // Default movement parameters (here for attacking)
var speed = 8f; float speed = 8f;
var inertia = 20f; float inertia = 20f;
if (foundTarget) if (foundTarget) {
{ Vector2 direction = targetCenter - Projectile.Center;
var direction = targetCenter - Projectile.Center;
direction.Normalize(); direction.Normalize();
if (distanceFromTarget > 40f) if (distanceFromTarget > 40f) {
{
// The immediate range around the target (so it doesn't latch onto it when close) // The immediate range around the target (so it doesn't latch onto it when close)
direction *= speed; direction *= speed;
Projectile.velocity = (Projectile.velocity * (inertia - 1) + direction) / inertia; Projectile.velocity = (Projectile.velocity * (inertia - 1) + direction) / inertia;
} }
switch (distanceFromTarget) if (distanceFromTarget <= 120f) {
{ attackMode = AttackMode.MELEE;
case <= 120f: }
_attackMode = AttackMode.Melee;
break; if (distanceFromTarget > 120f && shootCooldown == 0) {
case > 120f when _shootCooldown == 0: shootCooldown = 60; // 1 second between shots
{ Projectile laser = Projectile.NewProjectileDirect(player.GetSource_FromThis(), Projectile.Center,
_shootCooldown = 60; // 1 second between shots direction, ProjectileID.DeathLaser, 30, Projectile.knockBack, Projectile.owner);
var laser = Projectile.NewProjectileDirect(player.GetSource_FromThis(), Projectile.Center, laser.friendly = true;
direction, ProjectileID.DeathLaser, 30, Projectile.knockBack, Projectile.owner); laser.hostile = false;
laser.friendly = true; laser.penetrate = 5;
laser.hostile = false; attackMode = AttackMode.RANGED;
laser.penetrate = 5;
_attackMode = AttackMode.Ranged;
break;
}
} }
} }
else else {
{
// Minion doesn't have a target: return to player and idle // 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 up the minion if it's away from the player
speed = 12f; speed = 12f;
inertia = 60f; inertia = 60f;
} }
else else {
{
// Slow down the minion if closer to the player // Slow down the minion if closer to the player
speed = 4f; speed = 4f;
inertia = 80f; inertia = 80f;
} }
if (distanceToIdlePosition > 20f) if (distanceToIdlePosition > 20f) {
{
// The immediate range around the player (when it passively floats about) // 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 // This is a simple movement formula using the two parameters and its desired direction to create a "homing" movement
@@ -217,8 +197,7 @@ public class ToclafaneMinion : ModProjectile
vectorToIdlePosition *= speed; vectorToIdlePosition *= speed;
Projectile.velocity = (Projectile.velocity * (inertia - 1) + vectorToIdlePosition) / inertia; 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" // If there is a case where it's not moving at all, give it a little "poke"
Projectile.velocity.X = -0.15f; Projectile.velocity.X = -0.15f;
Projectile.velocity.Y = -0.05f; Projectile.velocity.Y = -0.05f;
@@ -232,67 +211,66 @@ public class ToclafaneMinion : ModProjectile
// So it will lean slightly towards the direction it's moving // So it will lean slightly towards the direction it's moving
Projectile.rotation = Projectile.velocity.X * 0.05f; Projectile.rotation = Projectile.velocity.X * 0.05f;
const int frameSpeed = 8; int frameSpeed = 8;
Projectile.frameCounter++; Projectile.frameCounter++;
if (Projectile.frameCounter >= frameSpeed) if (Projectile.frameCounter >= frameSpeed) {
{
Projectile.frameCounter = 0; Projectile.frameCounter = 0;
switch (_attackMode) if (attackMode == AttackMode.MELEE) {
{ switch (Projectile.frame) {
case AttackMode.Melee: case 0:
switch (Projectile.frame) Projectile.frame++;
{ break;
case 0: case 1:
case 1: Projectile.frame++;
case 2: break;
Projectile.frame++; case 2:
break; Projectile.frame++;
case 3: break;
Projectile.frame = 0; case 3:
break; Projectile.frame = 0;
case 4: break;
Projectile.frame = 1; case 4:
break; Projectile.frame = 1;
case 5: break;
Projectile.frame = 2; case 5:
break; Projectile.frame = 2;
case 6: break;
Projectile.frame = 3; case 6:
break; Projectile.frame = 3;
case 7: break;
Projectile.frame = 4; case 7:
break; Projectile.frame = 4;
} break;
}
}
break; if (attackMode == AttackMode.RANGED) {
case AttackMode.Ranged: switch (Projectile.frame) {
switch (Projectile.frame) case 0:
{ Projectile.frame = 5;
case 0: break;
Projectile.frame = 5; case 1:
break; Projectile.frame = 6;
case 1: break;
Projectile.frame = 6; case 2:
break; Projectile.frame = 7;
case 2: break;
Projectile.frame = 7; case 3:
break; Projectile.frame = 4;
case 3: break;
Projectile.frame = 4; case 4:
break; Projectile.frame++;
case 4: break;
case 5: case 5:
case 6: Projectile.frame++;
Projectile.frame++; break;
break; case 6:
case 7: Projectile.frame++;
Projectile.frame = 4; break;
break; case 7:
} Projectile.frame = 4;
break;
break; }
default:
break;
} }
} }
@@ -301,9 +279,8 @@ public class ToclafaneMinion : ModProjectile
#endregion #endregion
} }
private enum AttackMode enum AttackMode {
{ MELEE,
Melee, RANGED
Ranged,
} }
} }
-21
View File
@@ -1,21 +0,0 @@
using System;
using Terraria.ModLoader;
namespace YHTMod;
public class YhtPlayer : ModPlayer {
public int arcaneMissle = 0;
public int katanaTeleportCooldown = 0;
public override void PreUpdate() {
this.katanaTeleportCooldown = Math.Max(this.katanaTeleportCooldown - 1, 0);
}
public override void ResetEffects() {
this.arcaneMissle = 0;
base.ResetEffects();
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
displayName = YHT Mod displayName = YHT Mod
author = YouHaveTrouble author = YouHaveTrouble
version = 1.1.2 version = 1.0.1
-2
View File
@@ -1,7 +1,5 @@
Bunch of random additions ranging from QoL to random references Bunch of random additions ranging from QoL to random references
All new content and changes are documented on the wiki.
Wiki: https://github.com/YouHaveTrouble/YHTMod/wiki Wiki: https://github.com/YouHaveTrouble/YHTMod/wiki
Source: https://github.com/YouHaveTrouble/YHTMod Source: https://github.com/YouHaveTrouble/YHTMod
-4
View File
@@ -1,11 +1,7 @@
A bunch of random additions ranging from QoL to random references A bunch of random additions ranging from QoL to random references
Steam workshop: https://steamcommunity.com/sharedfiles/filedetails/?id=2897350075
Mod wiki: https://github.com/YouHaveTrouble/YHTMod/wiki Mod wiki: https://github.com/YouHaveTrouble/YHTMod/wiki
Discussion discord: [![Discord](https://img.shields.io/discord/821565102108573706?style=flat-square&color=%237289da&label=Discord)](https://discord.gg/j8KK5dGBps)
Code: YouHaveTrouble Code: YouHaveTrouble
Sprites: YouHaveTrouble, Patrxon Sprites: YouHaveTrouble, Patrxon