3526
Terrarian
hello i got a problem with the mod can anyone help me? i have made a thread about it here it is : (İ need help with the game. ) also please make your responses there.
Hello! I am super new to making mods for Terraria, but I am not super new to coding. However, I have never used C# before and I'm having some trouble.
I am currently trying to create a magic projectile that homes in on other players and heals them.
This is what I have for the projectile code:
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace xSHIGUYx.Weapons
{
public class BlessingofLifeP: ModProjectile
{
public override void SetDefaults()
{
projectile.Name = "Bless Bolt";
projectile.width = 16;
projectile.height = 16;
projectile.friendly = true;
projectile.aiStyle = 1;
projectile.extraUpdates = 1;
projectile.timeLeft = 300; //lasts for 300 frames/ticks. Terraria runs at 60FPS, so it lasts 5 seconds.
}
public override void OnHitPlayer(Projectile projectile, Player target, int damage, bool crit)
{
target.statLife += 10;
}
public override void AI()
{
int num1 = Dust.NewDust
(
projectile.position,
projectile.width,
projectile.height,
157,
projectile.velocity.X,
projectile.velocity.Y,
100,
default,
1f
);
Main.dust[num1].noGravity = true;
Main.dust[num1].velocity *= 0.1f;
for (int i = 1; i < 200; i++)
{
Player target = Main.player;
//Get the shoot trajectory from the projectile and target
float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X;
float shootToY = target.position.Y - projectile.Center.Y;
float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY));
//If the distance between the live targeted npc and the projectile is less than 480 pixels
if (distance < 480f && target.active)
{
//Divide the factor, 3f, which is the desired velocity
distance = 3f / distance;
//Multiply the distance by a multiplier if you wish the projectile to have go faster
shootToX *= distance * 5;
shootToY *= distance * 5;
//Set the velocities to the shoot values
projectile.velocity.X = shootToX;
projectile.velocity.Y = shootToY;
}
}
}
}
}
It currently is set to find a player other than the main player, due to the fact that I set "i" to 1. (If it's 0 it will home in on the casting player) And I'm not sure how to go about adding the heal mechanic. I've tried a plethora of methods, but I am just to unfamiliar with this language to make any real headway. All help is appreciated, thanks in advance!
Sorry about that! It copy and pasted strange, and in my code it is "Player target = Main.player[ i ]"Hello and welcome to the modding community! I am pretty new myself, but I seem to have enough knowledge to help out here in this thread.
There's indeed many ways to make a healing projectile. The reason your code doesn't work right now is because projectile.friendly is set to true, so the projectile will never hit a player. We can't change that, though, or else there will be more problems.
Before I help you, I am a bit confused with your target code. Is "Player target = Main.player;" supposed to be "Player target = Main.player;"?
I have some ideas already of how to solve your problem, but I would like to test them first, so keep a look out and I'll be back in a day or two.
Sorry about that! It copy and pasted strange, and in my code it is "Player target = Main.player[ i ]"
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace TestMod.Projectiles
{
public class BlessingofLifeP : ModProjectile
{
public override void SetDefaults()
{
projectile.Name = "Bless Bolt";
projectile.width = 16;
projectile.height = 16;
projectile.friendly = true;
projectile.aiStyle = 1;
projectile.extraUpdates = 1;
projectile.timeLeft = 300; //lasts for 300 frames/ticks. Terraria runs at 60FPS, so it lasts 5 seconds.
}
public override void AI()
{
int num1 = Dust.NewDust
(projectile.position,
projectile.width,projectile.height,
157,
projectile.velocity.X,
projectile.velocity.Y,
100,
default,
1f);
Main.dust[num1].noGravity = true;
Main.dust[num1].velocity *= 0.1f;
//since the for loop ticks 200 times, this keeps track if the player has been healed this tick
bool healed = false;
//projectile.ai[1] is being used to keep track of the time since the player was last healed
projectile.ai[1]++;
for (int i = 1; i < 200; i++)
{
Player target = Main.player[ i ];
//Get the shoot trajectory from the projectile and target
float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X;
float shootToY = target.position.Y - projectile.Center.Y;
float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY));
//how far the projectile can be from the player before triggering the effect
float margin = 0f;
//this if statement checks a few things
//1. Is the target active?
//2. Has the player been healed over the past 100 ticks? This amount controls how frequently the heal-over-time can be triggered. Currently it is set to 100, which means it can heal a max amount of three times (since projectile.timeleft is set to 300).
//3. Has the player been healed this tick yet?
//4. Is the projectile within range of healing the player?
if (target.active && projectile.ai[1] >= 100 && !healed && distance < 50f + margin && projectile.position.X < target.position.X + target.width + margin && projectile.position.X + projectile.width + margin > target.position.X && projectile.position.Y < target.position.Y + target.height + margin && projectile.position.Y + projectile.height + margin > target.position.Y)
{
//healing code here
//here's some example healing code
//heal amount
int heal = 10;
//prevent overheal
int damage = target.statLifeMax2 - target.statLife;
if (heal > damage)
{
heal = damage;
}
target.statLife += heal; //Heals for heal amount of Health
target.HealEffect(heal, true); //Creates heal visual
//kill the projectile here for one-time heal, and delete all referenes to healed and projectile.ai[1] since they would be unnecessary then
//projectile.Kill();
//the player has been healed
healed = true;
//reset timer
projectile.ai[1] = 0;
}
//If the distance between the live targeted npc and the projectile is less than 480 pixels
if (distance < 480f && target.active)
{
//Divide the factor, 3f, which is the desired velocity
distance = 3f / distance;
//Multiply the distance by a multiplier if you wish the projectile to have go faster
shootToX *= distance * 5;
shootToY *= distance * 5;
//Set the velocities to the shoot values
projectile.velocity.X = shootToX;
projectile.velocity.Y = shootToY;
}
}
}
}
}
I DID IT! It was actually really fun working on this. The result was a projectile that latches on to a player and heals them over time. If you want a one-time heal instead, there's instructions in the code. More explanation is also in the code. I did end up using projectile.ai[1] so keep that in mind.
Code:using Microsoft.Xna.Framework; using Terraria; using Terraria.ID; using Terraria.ModLoader; namespace TestMod.Projectiles { public class BlessingofLifeP : ModProjectile { public override void SetDefaults() { projectile.Name = "Bless Bolt"; projectile.width = 16; projectile.height = 16; projectile.friendly = true; projectile.aiStyle = 1; projectile.extraUpdates = 1; projectile.timeLeft = 300; //lasts for 300 frames/ticks. Terraria runs at 60FPS, so it lasts 5 seconds. } public override void AI() { int num1 = Dust.NewDust (projectile.position, projectile.width,projectile.height, 157, projectile.velocity.X, projectile.velocity.Y, 100, default, 1f); Main.dust[num1].noGravity = true; Main.dust[num1].velocity *= 0.1f; //since the for loop ticks 200 times, this keeps track if the player has been healed this tick bool healed = false; //projectile.ai[1] is being used to keep track of the time since the player was last healed projectile.ai[1]++; for (int i = 1; i < 200; i++) { Player target = Main.player[ i ]; //Get the shoot trajectory from the projectile and target float shootToX = target.position.X + (float)target.width * 0.5f - projectile.Center.X; float shootToY = target.position.Y - projectile.Center.Y; float distance = (float)System.Math.Sqrt((double)(shootToX * shootToX + shootToY * shootToY)); //how far the projectile can be from the player before triggering the effect float margin = 0f; //this if statement checks a few things //1. Is the target active? //2. Has the player been healed over the past 100 ticks? This amount controls how frequently the heal-over-time can be triggered. Currently it is set to 100, which means it can heal a max amount of three times (since projectile.timeleft is set to 300). //3. Has the player been healed this tick yet? //4. Is the projectile within range of healing the player? if (target.active && projectile.ai[1] >= 100 && !healed && distance < 50f + margin && projectile.position.X < target.position.X + target.width + margin && projectile.position.X + projectile.width + margin > target.position.X && projectile.position.Y < target.position.Y + target.height + margin && projectile.position.Y + projectile.height + margin > target.position.Y) { //healing code here //here's some example healing code //heal amount int heal = 10; //prevent overheal int damage = target.statLifeMax2 - target.statLife; if (heal > damage) { heal = damage; } target.statLife += heal; //Heals for heal amount of Health target.HealEffect(heal, true); //Creates heal visual //kill the projectile here for one-time heal, and delete all referenes to healed and projectile.ai[1] since they would be unnecessary then //projectile.Kill(); //the player has been healed healed = true; //reset timer projectile.ai[1] = 0; } //If the distance between the live targeted npc and the projectile is less than 480 pixels if (distance < 480f && target.active) { //Divide the factor, 3f, which is the desired velocity distance = 3f / distance; //Multiply the distance by a multiplier if you wish the projectile to have go faster shootToX *= distance * 5; shootToY *= distance * 5; //Set the velocities to the shoot values projectile.velocity.X = shootToX; projectile.velocity.Y = shootToY; } } } } }
P.S. Sorry that I might have messed up some code formatting, I'm quite a messy coder
P.P.S Figured out that [ i ] without spaces actually represents italic formatting in this forum, very annoying
P.P.P.S I don't actually know if the margin thingy works or not, haven't tested it lol. If it doesn't work, just ignore it, since your homing is fast enough to keep up with normal movement
Edit:
I forgot to put target.active in the if statement(I put it in now).
Also another p.s. because I'm forgetful:
I never tested your code in multiplayer, but the targeting code worked fine in singleplayer, so I assumed that it works perfectly. There might be some server sync issues with changing a player's health, I'm not sure.
public override void SetDefaults()
{
item.magic = true;
item.noMelee = true;
item.width = 30;
item.height = 32;
item.useTime = 17;
item.useAnimation = 17;
item.useStyle = ItemUseStyleID.HoldingUp;
if (Main.rand.Next(5) == 0)
{
item.shoot = mod.ProjectileType("VigorBoltAlt");
}
else
{
item.shoot = mod.ProjectileType("VigorBolt");
}
item.shootSpeed = 5f;
item.value = Item.sellPrice(gold: 3);
item.rare = ItemRarityID.Green;
item.UseSound = SoundID.Item28;
item.autoReuse = true;
item.useTurn = true;
item.mana = 35;
}
You shouldn't put any randomization in SetDefaults()Hey, thank you so much! This works perfectly, and it gives me a little more insight on how to code for health mechanics in terraria! All in all, I'm really grateful you did this! Once again, thank you!However, I tried building on the system to add a randomized projectile generation for the spell, and it didn't seem to work? Any thoughts?
NEVER MIND I'VE GOT IT TO WORK! Yay for independent learning!
Here's the code snippet:
Code:public override void SetDefaults() { item.magic = true; item.noMelee = true; item.width = 30; item.height = 32; item.useTime = 17; item.useAnimation = 17; item.useStyle = ItemUseStyleID.HoldingUp; if (Main.rand.Next(5) == 0) { item.shoot = mod.ProjectileType("VigorBoltAlt"); } else { item.shoot = mod.ProjectileType("VigorBolt"); } item.shootSpeed = 5f; item.value = Item.sellPrice(gold: 3); item.rare = ItemRarityID.Green; item.UseSound = SoundID.Item28; item.autoReuse = true; item.useTurn = true; item.mana = 35; }
You can take a look at Example Mod for some reference, here: tModLoader/tModLoaderCan you do a guide on how to make modded armour? I'm confused about all the textures.
You shouldn't put any randomization in SetDefaults()
Everytime an item is generated, so when it drops, or you load your player, it will be shooting one of those at random. It means you can have found the weapon shooting projectile A, but next time you play it might be shooting projectile B. If you want the projectile it shoots to be random, override the Shoot hook and put your randomization logic in there. Change the type parameter to the random projectile type.
public override bool Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack)
{
if (Main.rand.Next(5) == 0)
{
item.shoot = mod.ProjectileType("BlessingofVigorPalt");
}
else
{
item.shoot = mod.ProjectileType("BlessingofVigorP");
}
return true;
}
You should set the ref type parameter though, not item.shoot.Yeah, that's what I ended up doing. I left in the code from when I couldn't get it to work as an example of my bad code. Guess I should've showed the proper code as well:
Code:public override bool Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack) { if (Main.rand.Next(5) == 0) { item.shoot = mod.ProjectileType("BlessingofVigorPalt"); } else { item.shoot = mod.ProjectileType("BlessingofVigorP"); } return true; }
That's because you clone the item, and it will 'use' the original projectile. That projectile has the original sprite.Hi I've got a Question to the tmodloader.
I'm trying to make a weak version of the Medusa Head dropped from the Eye of Cuthulu. It has a different icon, but if I use it it only shows the original medusahead.
That's my code so far.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace TestMod.Items
{
public class EyeOfTerror : ModItem
{
public override void SetDefaults()
{
item.CloneDefaults(ItemID.MedusaHead);
item.damage = 2;
item.mana = 2;
item.knockBack = 5;
item.value = 1000;
item.rare = 2;
item.autoReuse = true;
}
}
}
I'm trying to make a projectile with a giant hitbox. But it seems like damage is only aplied when the sprite hits the target. How can I make the projectile hit every enemy within a specific range.
public class IceBiomeInfo
{
public int EndOfBiome { get; set; }
public int StartOfBiome { get; set; }
public int SurfaceOfBiome { get; set; }
public int DepthOfBiome { get; set; }
public int WidthOfBiome { get => EndOfBiome - StartOfBiome; }
public int HeightOfBiome { get => DepthOfBiome - SurfaceOfBiome; }
public static List<int> TileTypeContent { get; } = new List<int>
{
ModContent.TileType<SmoothIceBlock>(),
TileID.SnowBlock,
TileID.IceBlock,
TileID.Slush,
TileID.BreakableIce,
};
// Need to find an other way to get those...
public static int[] TileOverrideAllowed { get; set; } = new int[]
{
TileID.Dirt,
TileID.Stone,
TileID.FossilOre,
TileID.WoodBlock,
TileID.Stalactite,
TileID.Mud,
TileID.Diamond,
TileID.DiamondGemspark,
TileID.Ruby,
TileID.RubyGemspark,
TileID.Sapphire,
TileID.SapphireGemspark,
TileID.Topaz,
TileID.TopazGemspark,
TileID.BorealWood,
TileID.Platforms,
TileID.ClosedDoor,
TileID.Copper,
TileID.Tin,
TileID.Iron,
TileID.Lead,
TileID.Silver,
TileID.Tungsten,
TileID.Platinum,
TileID.Gold,
};
public IceBiomeInfo() { }
public IceBiomeInfo(int StartOfBiome, int EndOfBiome, int WidthOfBiome = 0, int SurfaceOfBiome = 0, int DepthOfBiome = 0, int HeightOfBiome = 0)
{
this.EndOfBiome = EndOfBiome;
this.StartOfBiome = StartOfBiome;
this.SurfaceOfBiome = SurfaceOfBiome;
this.DepthOfBiome = DepthOfBiome;
}
}
// Todo: Add a dungeon check
private IceBiomeInfo FindNewIceBiomePositions(int minBiomeSize)
{
int maxTry = 10;
int minX = 0;
int minY = new Vector2(0,(float)Main.worldSurface).ToTileCoordinates().Y;
int tryPass = 0;
Point Cursor = new Point(minX, minY);
IceBiomeInfo info = new IceBiomeInfo();
// Find a dirt biome or sand biome
while(info.WidthOfBiome == 0 && tryPass < maxTry)
{
tryPass++;
minX = Main.rand.Next(0, Main.maxTilesX);
Cursor.X = minX;
if (Main.tile[Cursor.X, Cursor.Y] == null ||
!IceBiomeInfo.TileTypeContent.Contains(Main.tile[Cursor.X, Cursor.Y].type) &&
(IceBiomeInfo.TileOverrideAllowed.Contains(Main.tile[Cursor.X, Cursor.Y].type) || !Main.tile[Cursor.X, Cursor.Y].active()))
{
// Get biome width
while (Cursor.X < Main.maxTilesX && IceBiomeInfo.TileOverrideAllowed.Contains(Main.tile[Cursor.X, Cursor.Y].type))
{
Cursor.X++;
}
if(Cursor.X - minX > minBiomeSize)
{
info.StartOfBiome = minX;
info.EndOfBiome = Cursor.X;
int skyAssurance = 50;
int currentAssurance = 0;
// Get surface line
while(IceBiomeInfo.TileOverrideAllowed.Contains(Main.tile[Cursor.X, Cursor.Y].type) && currentAssurance < skyAssurance)
{
Cursor.Y--;
if(!Main.tile[Cursor.X, Cursor.Y].active())
{
while (currentAssurance < skyAssurance && !(Main.tile[Cursor.X, Cursor.Y] == null || Main.tile[Cursor.X, Cursor.Y].active()))
{
Cursor.Y--;
currentAssurance++;
}
}
}
info.SurfaceOfBiome = Cursor.Y;
info.DepthOfBiome = WorldGen.lavaLine / 16;
}
}
}
return info;
}
public override void ModifyWorldGenTasks(List<GenPass> tasks, ref float totalWeight)
{
int iceIndex = tasks.FindIndex(x => x.Name == "Shinies") + 1;
if (iceIndex != -1)
{
tasks.Insert(iceIndex, new PassLegacy("MoreIce", MoreIcePlease));
}
else
{
Main.NewText("No ice Index Found", 255, 0, 0, true);
}
}
private void MoreIcePlease(GenerationProgress progress)
{
progress.Message = "Give me more Ice!";
IceBiomeInfo iceBiomeInfo = FindNewIceBiomePositions(500);
for(int i = iceBiomeInfo.StartOfBiome; i < iceBiomeInfo.EndOfBiome; i++)
{
for (int j = iceBiomeInfo.SurfaceOfBiome; j < iceBiomeInfo.DepthOfBiome; j++)
{
WorldGen.TileRunner(i, j, 6, Main.rand.Next(1, 3), TileID.IceBlock, true, 0f, 0f, true, true);
}
}
}
public override void MeleeEffects(Player player, Rectangle hitbox) {
player.HealEffect(5, true);
}
I got following Problem I'm writing a script for a weapon. It is supposed to heal you if you swing it. When I use this code I get a lot of green signs. But I don't get any as healing I need it because it should remove the damage of a explosive that is fired by it and damages the player, too.
C#:public override void MeleeEffects(Player player, Rectangle hitbox) { player.HealEffect(5, true); }
public override void SetDefaults()
{
item.healLife = 5;
}