tModLoader Explosives

Lavendarjosh

Eye of Cthulhu
So I literally started modding (and coding) two days ago, but I'm working on an explosives focused mod.

I tried to read into the ExampleExplosives.cs from the wiki, but it's pretty complicated, and I would prefer to modify vanilla explosives.
My main two questions are: how can I alter the explosion radius of things like dynamite and placable explosives, and is there a way to make shaped explosions?
Like 7 blocks wide and 30 blocks deep? And if not, how do I make dynamite, for example, respawn itself n times in a set direction?
Any help and pointers are greatly appreciated.

EDIT: when I say 'modify' I mean using CloneDefaults, not actually changing the vanilla items and projectiles.
 
Last edited:
So I literally started modding (and coding) two days ago, but I'm working on an explosives focused mod.

I tried to read into the ExampleExplosives.cs from the wiki, but it's pretty complicated, and I would prefer to modify vanilla explosives.
My main two questions are: how can I alter the explosion radius of things like dynamite and placable explosives, and is there a way to make shaped explosions?
Like 7 blocks wide and 30 blocks deep? And if not, how do I make dynamite, for example, respawn itself n times in a set direction?
Any help and pointers are greatly appreciated.

EDIT: when I say 'modify' I mean using CloneDefaults, not actually changing the vanilla items and projectiles.
Unfortunately, the explosive AI style cannot be modified this easily. The explosive AI is static and is unable to be changed directly so there is no easy way of changing the radius of an explosion using defaults, so you would have to code your own explosive projectile if you want to make a definitive radius.
 
Well that's a shame, I was hoping for an easy way.
Time to take apart the example...
Honestly the ExampleExplosive is the absolute easiest example of an explosion you can hope for with the customization you desire. Yeah, just read it line by line. Start with custom explosion before attempting modifying vanilla.
 
  • Like
Reactions: 000
I played around with the example a bit and managed to make it act like about the way I want it to, I just have a small problem: instead of being a good dynamite stick and explode after its 8 seconds fusetime, it just explodes on contact with a tile, and I have no idea why. Code below.

Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.GameContent.Achievements;

namespace Boombastic.Projectiles
{
  // to investigate: Projectile.Damage, (8843)
  class SuperDynamite : ModProjectile
  {
  public override void SetDefaults()
  {
  projectile.name = "Super Dynamite";
  // while the sprite is actually bigger than 15x15, we use 15x15 since it lets the projectile clip into tiles as it bounces. It looks better.
  projectile.width = 15;
  projectile.height = 15;
  projectile.friendly = false;
  projectile.penetrate = -1;

  // 8 second fuse.
  projectile.timeLeft = 480;

  // These 2 help the projectile hitbox be centered on the projectile sprite.
  drawOffsetX = 5;
  drawOriginOffsetY = 5;
  }


  public override void AI()
  {
  if (projectile.owner == Main.myPlayer && projectile.timeLeft <= 3)
  {
  projectile.tileCollide = false;
  // Set to transparant. This projectile technically lives as  transparant for about 3 frames
  projectile.alpha = 255;
  // change the hitbox size, centered about the original projectile center. This makes the projectile damage enemies during the explosion.
  projectile.position.X = projectile.position.X + (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y + (float)(projectile.height / 2);
  projectile.width = 250;
  projectile.height = 250;
  projectile.position.X = projectile.position.X - (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y - (float)(projectile.height / 2);
  projectile.damage = 400;
  projectile.knockBack = 10f;
  }
  else
  {
  // Smoke and fuse dust spawn.
  if (Main.rand.Next(2) == 0)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 31, 0f, 0f, 100, default(Color), 1f);
  Main.dust[dustIndex].scale = 0.1f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].fadeIn = 1.5f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].position = projectile.Center + new Vector2(0f, (float)(-(float)projectile.height / 2)).RotatedBy((double)projectile.rotation, default(Vector2)) * 1.1f;
  dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 1f);
  Main.dust[dustIndex].scale = 1f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].position = projectile.Center + new Vector2(0f, (float)(-(float)projectile.height / 2 - 6)).RotatedBy((double)projectile.rotation, default(Vector2)) * 1.1f;
  }
  }
  projectile.ai[0] += 1f;
  if (projectile.ai[0] > 5f)
  {
  projectile.ai[0] = 10f;
  // Roll speed dampening.
  if (projectile.velocity.Y == 0f && projectile.velocity.X != 0f)
  {
  projectile.velocity.X = projectile.velocity.X * 0.97f;
  //if (projectile.type == 29 || projectile.type == 470 || projectile.type == 637)
  {
  projectile.velocity.X = projectile.velocity.X * 0.99f;
  }
  if ((double)projectile.velocity.X > -0.01 && (double)projectile.velocity.X < 0.01)
  {
  projectile.velocity.X = 0f;
  projectile.netUpdate = true;
  }
  }
  projectile.velocity.Y = projectile.velocity.Y + 0.2f;
  }
  // Rotation increased by velocity.X
  projectile.rotation += projectile.velocity.X * 0.1f;
  return;
  }

  public override void Kill(int timeLeft)
  {
  /*
  // If we are the original projectile, spawn the 5 child projectiles
  if (projectile.ai[1] == 0)
  {
  for (int i = 0; i < 5; i++)
  {
  // Random upward vector.
  Vector2 vel = new Vector2(Main.rand.NextFloat(0, 0), Main.rand.NextFloat(0, 0));
  Projectile.NewProjectile(projectile.Center, vel, projectile.type, projectile.damage, projectile.knockBack, projectile.owner, 0, 1);
  }
  }
  */
  // Play explosion sound
  Main.PlaySound(SoundID.Item14, projectile.position);
  // Smoke Dust spawn
  for (int i = 0; i < 50; i++)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 31, 0f, 0f, 100, default(Color), 2f);
  Main.dust[dustIndex].velocity *= 1.4f;
  }
  // Fire Dust spawn
  for (int i = 0; i < 80; i++)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 3f);
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].velocity *= 5f;
  dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 2f);
  Main.dust[dustIndex].velocity *= 3f;
  }
  // Large Smoke Gore spawn
  for (int g = 0; g < 2; g++)
  {
  int goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X + 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y + 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X - 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y + 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X + 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y - 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X - 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y - 1.5f;
  }
  // reset size to normal width and height.
  projectile.position.X = projectile.position.X + (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y + (float)(projectile.height / 2);
  projectile.width = 10;
  projectile.height = 10;
  projectile.position.X = projectile.position.X - (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y - (float)(projectile.height / 2);

  // TODO, tmodloader helper method
  {
  int explosionRadius = 9;
  //if (projectile.type == 29 || projectile.type == 470 || projectile.type == 637)
  //{
  //  explosionRadius = 15;
  //}
  int minTileX = (int)(projectile.position.X / 16f - (float)explosionRadius);
  int maxTileX = (int)(projectile.position.X / 16f + (float)explosionRadius);
  int minTileY = (int)(projectile.position.Y / 16f - (float)explosionRadius);
  int maxTileY = (int)(projectile.position.Y / 16f + (float)explosionRadius);
  if (minTileX < 0)
  {
  minTileX = 0;
  }
  if (maxTileX > Main.maxTilesX)
  {
  maxTileX = Main.maxTilesX;
  }
  if (minTileY < 0)
  {
  minTileY = 0;
  }
  if (maxTileY > Main.maxTilesY)
  {
  maxTileY = Main.maxTilesY;
  }
  bool canKillWalls = false;
  for (int x = minTileX; x <= maxTileX; x++)
  {
  for (int y = minTileY; y <= maxTileY; y++)
  {
  float diffX = Math.Abs((float)x - projectile.position.X / 16f);
  float diffY = Math.Abs((float)y - projectile.position.Y / 16f);
  double distance = Math.Sqrt((double)(diffX * diffX + diffY * diffY));
  if (distance < (double)explosionRadius && Main.tile[x, y] != null && Main.tile[x, y].wall == 0)
  {
  canKillWalls = true;
  break;
  }
  }
  }
  AchievementsHelper.CurrentlyMining = true;
  for (int i = minTileX; i <= maxTileX; i++)
  {
  for (int j = minTileY; j <= maxTileY; j++)
  {
  float diffX = Math.Abs((float)i - projectile.position.X / 16f);
  float diffY = Math.Abs((float)j - projectile.position.Y / 16f);
  double distanceToTile = Math.Sqrt((double)(diffX * diffX + diffY * diffY));
  if (distanceToTile < (double)explosionRadius)
  {
  bool canKillTile = true;
  if (Main.tile[i, j] != null && Main.tile[i, j].active())
  {
  canKillTile = true;
  if (Main.tileDungeon[(int)Main.tile[i, j].type] || Main.tile[i, j].type == 88 || Main.tile[i, j].type == 21 || Main.tile[i, j].type == 26 || Main.tile[i, j].type == 107 || Main.tile[i, j].type == 108 || Main.tile[i, j].type == 111 || Main.tile[i, j].type == 226 || Main.tile[i, j].type == 237 || Main.tile[i, j].type == 221 || Main.tile[i, j].type == 222 || Main.tile[i, j].type == 223 || Main.tile[i, j].type == 211 || Main.tile[i, j].type == 404)
  {
  canKillTile = false;
  }
  if (!Main.hardMode && Main.tile[i, j].type == 58)
  {
  canKillTile = false;
  }
  if (!TileLoader.CanExplode(i, j))
  {
  canKillTile = false;
  }
  if (canKillTile)
  {
  WorldGen.KillTile(i, j, false, false, false);
  if (!Main.tile[i, j].active() && Main.netMode != 0)
  {
  NetMessage.SendData(17, -1, -1, "", 0, (float)i, (float)j, 0f, 0, 0, 0);
  }
  }
  }
  if (canKillTile)
  {
  for (int x = i - 1; x <= i + 1; x++)
  {
  for (int y = j - 1; y <= j + 1; y++)
  {
  if (Main.tile[x, y] != null && Main.tile[x, y].wall > 0 && canKillWalls && WallLoader.CanExplode(x, y, Main.tile[x, y].wall))
  {
  WorldGen.KillWall(x, y, false);
  if (Main.tile[x, y].wall == 0 && Main.netMode != 0)
  {
  NetMessage.SendData(17, -1, -1, "", 2, (float)x, (float)y, 0f, 0, 0, 0);
  }
  }
  }
  }
  }
  }
  }
  }
  AchievementsHelper.CurrentlyMining = false;
  }
  }
  }
}
There's still a lot of junk in it, but I don't want to break it by touching anything I don't know the effect of.
 
I played around with the example a bit and managed to make it act like about the way I want it to, I just have a small problem: instead of being a good dynamite stick and explode after its 8 seconds fusetime, it just explodes on contact with a tile, and I have no idea why. Code below.

Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.GameContent.Achievements;

namespace Boombastic.Projectiles
{
  // to investigate: Projectile.Damage, (8843)
  class SuperDynamite : ModProjectile
  {
  public override void SetDefaults()
  {
  projectile.name = "Super Dynamite";
  // while the sprite is actually bigger than 15x15, we use 15x15 since it lets the projectile clip into tiles as it bounces. It looks better.
  projectile.width = 15;
  projectile.height = 15;
  projectile.friendly = false;
  projectile.penetrate = -1;

  // 8 second fuse.
  projectile.timeLeft = 480;

  // These 2 help the projectile hitbox be centered on the projectile sprite.
  drawOffsetX = 5;
  drawOriginOffsetY = 5;
  }


  public override void AI()
  {
  if (projectile.owner == Main.myPlayer && projectile.timeLeft <= 3)
  {
  projectile.tileCollide = false;
  // Set to transparant. This projectile technically lives as  transparant for about 3 frames
  projectile.alpha = 255;
  // change the hitbox size, centered about the original projectile center. This makes the projectile damage enemies during the explosion.
  projectile.position.X = projectile.position.X + (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y + (float)(projectile.height / 2);
  projectile.width = 250;
  projectile.height = 250;
  projectile.position.X = projectile.position.X - (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y - (float)(projectile.height / 2);
  projectile.damage = 400;
  projectile.knockBack = 10f;
  }
  else
  {
  // Smoke and fuse dust spawn.
  if (Main.rand.Next(2) == 0)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 31, 0f, 0f, 100, default(Color), 1f);
  Main.dust[dustIndex].scale = 0.1f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].fadeIn = 1.5f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].position = projectile.Center + new Vector2(0f, (float)(-(float)projectile.height / 2)).RotatedBy((double)projectile.rotation, default(Vector2)) * 1.1f;
  dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 1f);
  Main.dust[dustIndex].scale = 1f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].position = projectile.Center + new Vector2(0f, (float)(-(float)projectile.height / 2 - 6)).RotatedBy((double)projectile.rotation, default(Vector2)) * 1.1f;
  }
  }
  projectile.ai[0] += 1f;
  if (projectile.ai[0] > 5f)
  {
  projectile.ai[0] = 10f;
  // Roll speed dampening.
  if (projectile.velocity.Y == 0f && projectile.velocity.X != 0f)
  {
  projectile.velocity.X = projectile.velocity.X * 0.97f;
  //if (projectile.type == 29 || projectile.type == 470 || projectile.type == 637)
  {
  projectile.velocity.X = projectile.velocity.X * 0.99f;
  }
  if ((double)projectile.velocity.X > -0.01 && (double)projectile.velocity.X < 0.01)
  {
  projectile.velocity.X = 0f;
  projectile.netUpdate = true;
  }
  }
  projectile.velocity.Y = projectile.velocity.Y + 0.2f;
  }
  // Rotation increased by velocity.X
  projectile.rotation += projectile.velocity.X * 0.1f;
  return;
  }

  public override void Kill(int timeLeft)
  {
  /*
  // If we are the original projectile, spawn the 5 child projectiles
  if (projectile.ai[1] == 0)
  {
  for (int i = 0; i < 5; i++)
  {
  // Random upward vector.
  Vector2 vel = new Vector2(Main.rand.NextFloat(0, 0), Main.rand.NextFloat(0, 0));
  Projectile.NewProjectile(projectile.Center, vel, projectile.type, projectile.damage, projectile.knockBack, projectile.owner, 0, 1);
  }
  }
  */
  // Play explosion sound
  Main.PlaySound(SoundID.Item14, projectile.position);
  // Smoke Dust spawn
  for (int i = 0; i < 50; i++)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 31, 0f, 0f, 100, default(Color), 2f);
  Main.dust[dustIndex].velocity *= 1.4f;
  }
  // Fire Dust spawn
  for (int i = 0; i < 80; i++)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 3f);
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].velocity *= 5f;
  dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 2f);
  Main.dust[dustIndex].velocity *= 3f;
  }
  // Large Smoke Gore spawn
  for (int g = 0; g < 2; g++)
  {
  int goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X + 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y + 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X - 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y + 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X + 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y - 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X - 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y - 1.5f;
  }
  // reset size to normal width and height.
  projectile.position.X = projectile.position.X + (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y + (float)(projectile.height / 2);
  projectile.width = 10;
  projectile.height = 10;
  projectile.position.X = projectile.position.X - (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y - (float)(projectile.height / 2);

  // TODO, tmodloader helper method
  {
  int explosionRadius = 9;
  //if (projectile.type == 29 || projectile.type == 470 || projectile.type == 637)
  //{
  //  explosionRadius = 15;
  //}
  int minTileX = (int)(projectile.position.X / 16f - (float)explosionRadius);
  int maxTileX = (int)(projectile.position.X / 16f + (float)explosionRadius);
  int minTileY = (int)(projectile.position.Y / 16f - (float)explosionRadius);
  int maxTileY = (int)(projectile.position.Y / 16f + (float)explosionRadius);
  if (minTileX < 0)
  {
  minTileX = 0;
  }
  if (maxTileX > Main.maxTilesX)
  {
  maxTileX = Main.maxTilesX;
  }
  if (minTileY < 0)
  {
  minTileY = 0;
  }
  if (maxTileY > Main.maxTilesY)
  {
  maxTileY = Main.maxTilesY;
  }
  bool canKillWalls = false;
  for (int x = minTileX; x <= maxTileX; x++)
  {
  for (int y = minTileY; y <= maxTileY; y++)
  {
  float diffX = Math.Abs((float)x - projectile.position.X / 16f);
  float diffY = Math.Abs((float)y - projectile.position.Y / 16f);
  double distance = Math.Sqrt((double)(diffX * diffX + diffY * diffY));
  if (distance < (double)explosionRadius && Main.tile[x, y] != null && Main.tile[x, y].wall == 0)
  {
  canKillWalls = true;
  break;
  }
  }
  }
  AchievementsHelper.CurrentlyMining = true;
  for (int i = minTileX; i <= maxTileX; i++)
  {
  for (int j = minTileY; j <= maxTileY; j++)
  {
  float diffX = Math.Abs((float)i - projectile.position.X / 16f);
  float diffY = Math.Abs((float)j - projectile.position.Y / 16f);
  double distanceToTile = Math.Sqrt((double)(diffX * diffX + diffY * diffY));
  if (distanceToTile < (double)explosionRadius)
  {
  bool canKillTile = true;
  if (Main.tile[i, j] != null && Main.tile[i, j].active())
  {
  canKillTile = true;
  if (Main.tileDungeon[(int)Main.tile[i, j].type] || Main.tile[i, j].type == 88 || Main.tile[i, j].type == 21 || Main.tile[i, j].type == 26 || Main.tile[i, j].type == 107 || Main.tile[i, j].type == 108 || Main.tile[i, j].type == 111 || Main.tile[i, j].type == 226 || Main.tile[i, j].type == 237 || Main.tile[i, j].type == 221 || Main.tile[i, j].type == 222 || Main.tile[i, j].type == 223 || Main.tile[i, j].type == 211 || Main.tile[i, j].type == 404)
  {
  canKillTile = false;
  }
  if (!Main.hardMode && Main.tile[i, j].type == 58)
  {
  canKillTile = false;
  }
  if (!TileLoader.CanExplode(i, j))
  {
  canKillTile = false;
  }
  if (canKillTile)
  {
  WorldGen.KillTile(i, j, false, false, false);
  if (!Main.tile[i, j].active() && Main.netMode != 0)
  {
  NetMessage.SendData(17, -1, -1, "", 0, (float)i, (float)j, 0f, 0, 0, 0);
  }
  }
  }
  if (canKillTile)
  {
  for (int x = i - 1; x <= i + 1; x++)
  {
  for (int y = j - 1; y <= j + 1; y++)
  {
  if (Main.tile[x, y] != null && Main.tile[x, y].wall > 0 && canKillWalls && WallLoader.CanExplode(x, y, Main.tile[x, y].wall))
  {
  WorldGen.KillWall(x, y, false);
  if (Main.tile[x, y].wall == 0 && Main.netMode != 0)
  {
  NetMessage.SendData(17, -1, -1, "", 2, (float)x, (float)y, 0f, 0, 0, 0);
  }
  }
  }
  }
  }
  }
  }
  }
  AchievementsHelper.CurrentlyMining = false;
  }
  }
  }
}
There's still a lot of junk in it, but I don't want to break it by touching anything I don't know the effect of.
Where is you OnTileCollide? You seem to have deleted that, but it all works together, so you shouldn't do that.
 
Okay, next problem I've run into (hopefully the last for now):
I managed to make placeable explosives with a bigger bang, but I don't know how to make the tile disappear like with regular explosives.
Haven't found an example that does something similar.

Here's the code I have so far:
Code:
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Terraria.GameContent.Achievements;

namespace Boombastic.Projectiles
{
  // to investigate: Projectile.Damage, (8843)
  class MOAB : ModProjectile
  {
  public override void SetDefaults()
  {
  projectile.name = "M.O.A.B.";
  // while the sprite is actually bigger than 15x15, we use 15x15 since it lets the projectile clip into tiles as it bounces. It looks better.
  projectile.width = 15;
  projectile.height = 15;
  projectile.friendly = false;
  projectile.hostile = true;
  projectile.penetrate = -1;

  // 8 second fuse.
  projectile.timeLeft = 4;

  // These 2 help the projectile hitbox be centered on the projectile sprite.
  drawOffsetX = 5;
  drawOriginOffsetY = 5;
  }

  public override bool OnTileCollide(Vector2 oldVelocity)
  {
  // Die immediately if ai[1] isn't 0 (We set this to 1 for the 5 extra explosives we spawn in Kill)
  if (projectile.ai[1] != 0)
  {
  return true;
  }

  return false;
  }

  public override void AI()
  {
  if (projectile.owner == Main.myPlayer && projectile.timeLeft <= 3)
  {
  projectile.tileCollide = false;
  // Set to transparant. This projectile technically lives as  transparant for about 3 frames
  projectile.alpha = 255;
  // change the hitbox size, centered about the original projectile center. This makes the projectile damage enemies during the explosion.
  projectile.position.X = projectile.position.X + (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y + (float)(projectile.height / 2);
  projectile.width = 250;
  projectile.height = 250;
  projectile.position.X = projectile.position.X - (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y - (float)(projectile.height / 2);
  projectile.damage = 5000;
  projectile.knockBack = 20f;
  }
  else
  {
  // Smoke and fuse dust spawn.
  if (Main.rand.Next(2) == 0)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 31, 0f, 0f, 100, default(Color), 1f);
  Main.dust[dustIndex].scale = 0.1f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].fadeIn = 1.5f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].position = projectile.Center + new Vector2(0f, (float)(-(float)projectile.height / 2)).RotatedBy((double)projectile.rotation, default(Vector2)) * 1.1f;
  dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 1f);
  Main.dust[dustIndex].scale = 1f + (float)Main.rand.Next(5) * 0.1f;
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].position = projectile.Center + new Vector2(0f, (float)(-(float)projectile.height / 2 - 6)).RotatedBy((double)projectile.rotation, default(Vector2)) * 1.1f;
  }
  }
  projectile.ai[0] += 1f;
  if (projectile.ai[0] > 5f)
  {
  projectile.ai[0] = 10f;
  // Roll speed dampening.
  if (projectile.velocity.Y == 0f && projectile.velocity.X != 0f)
  {
  projectile.velocity.X = projectile.velocity.X * 0.97f;
  //if (projectile.type == 29 || projectile.type == 470 || projectile.type == 637)
  {
  projectile.velocity.X = projectile.velocity.X * 0.99f;
  }
  if ((double)projectile.velocity.X > -0.01 && (double)projectile.velocity.X < 0.01)
  {
  projectile.velocity.X = 0f;
  projectile.netUpdate = true;
  }
  }
  projectile.velocity.Y = projectile.velocity.Y + 0.2f;
  }
  // Rotation increased by velocity.X
  projectile.rotation += projectile.velocity.X * 0.1f;
  return;
  }

  public override void Kill(int timeLeft)
  {
  /*
  // If we are the original projectile, spawn the 5 child projectiles
  if (projectile.ai[1] == 0)
  {
  for (int i = 0; i < 5; i++)
  {
  // Random upward vector.
  Vector2 vel = new Vector2(Main.rand.NextFloat(0, 0), Main.rand.NextFloat(0, 0));
  Projectile.NewProjectile(projectile.Center, vel, projectile.type, projectile.damage, projectile.knockBack, projectile.owner, 0, 1);
  }
  }
  */
  // Play explosion sound
  Main.PlaySound(SoundID.Item14, projectile.position).WithVolume(1.5f);
  // Smoke Dust spawn
  for (int i = 0; i < 50; i++)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 31, 0f, 0f, 100, default(Color), 2f);
  Main.dust[dustIndex].velocity *= 1.4f;
  }
  // Fire Dust spawn
  for (int i = 0; i < 80; i++)
  {
  int dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 3f);
  Main.dust[dustIndex].noGravity = true;
  Main.dust[dustIndex].velocity *= 5f;
  dustIndex = Dust.NewDust(new Vector2(projectile.position.X, projectile.position.Y), projectile.width, projectile.height, 6, 0f, 0f, 100, default(Color), 2f);
  Main.dust[dustIndex].velocity *= 3f;
  }
  // Large Smoke Gore spawn
  for (int g = 0; g < 2; g++)
  {
  int goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X + 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y + 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X - 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y + 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X + 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y - 1.5f;
  goreIndex = Gore.NewGore(new Vector2(projectile.position.X + (float)(projectile.width / 2) - 24f, projectile.position.Y + (float)(projectile.height / 2) - 24f), default(Vector2), Main.rand.Next(61, 64), 1f);
  Main.gore[goreIndex].scale = 1.5f;
  Main.gore[goreIndex].velocity.X = Main.gore[goreIndex].velocity.X - 1.5f;
  Main.gore[goreIndex].velocity.Y = Main.gore[goreIndex].velocity.Y - 1.5f;
  }
  // reset size to normal width and height.
  projectile.position.X = projectile.position.X + (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y + (float)(projectile.height / 2);
  projectile.width = 10;
  projectile.height = 10;
  projectile.position.X = projectile.position.X - (float)(projectile.width / 2);
  projectile.position.Y = projectile.position.Y - (float)(projectile.height / 2);

  // TODO, tmodloader helper method
  {
  int explosionRadius = 32;
  //if (projectile.type == 29 || projectile.type == 470 || projectile.type == 637)
  //{
  //  explosionRadius = 15;
  //}
  int minTileX = (int)(projectile.position.X / 16f - (float)explosionRadius);
  int maxTileX = (int)(projectile.position.X / 16f + (float)explosionRadius);
  int minTileY = (int)(projectile.position.Y / 16f - (float)explosionRadius);
  int maxTileY = (int)(projectile.position.Y / 16f + (float)explosionRadius);
  if (minTileX < 0)
  {
  minTileX = 0;
  }
  if (maxTileX > Main.maxTilesX)
  {
  maxTileX = Main.maxTilesX;
  }
  if (minTileY < 0)
  {
  minTileY = 0;
  }
  if (maxTileY > Main.maxTilesY)
  {
  maxTileY = Main.maxTilesY;
  }
  bool canKillWalls = false;
  for (int x = minTileX; x <= maxTileX; x++)
  {
  for (int y = minTileY; y <= maxTileY; y++)
  {
  float diffX = Math.Abs((float)x - projectile.position.X / 16f);
  float diffY = Math.Abs((float)y - projectile.position.Y / 16f);
  double distance = Math.Sqrt((double)(diffX * diffX + diffY * diffY));
  if (distance < (double)explosionRadius && Main.tile[x, y] != null && Main.tile[x, y].wall == 0)
  {
  canKillWalls = true;
  break;
  }
  }
  }
  AchievementsHelper.CurrentlyMining = true;
  for (int i = minTileX; i <= maxTileX; i++)
  {
  for (int j = minTileY; j <= maxTileY; j++)
  {
  float diffX = Math.Abs((float)i - projectile.position.X / 16f);
  float diffY = Math.Abs((float)j - projectile.position.Y / 16f);
  double distanceToTile = Math.Sqrt((double)(diffX * diffX + diffY * diffY));
  if (distanceToTile < (double)explosionRadius)
  {
  bool canKillTile = true;
  if (Main.tile[i, j] != null && Main.tile[i, j].active())
  {
  canKillTile = true;
  if (Main.tileDungeon[(int)Main.tile[i, j].type] || Main.tile[i, j].type == 88 || Main.tile[i, j].type == 21 || Main.tile[i, j].type == 26 || Main.tile[i, j].type == 107 || Main.tile[i, j].type == 108 || Main.tile[i, j].type == 111 || Main.tile[i, j].type == 226 || Main.tile[i, j].type == 237 || Main.tile[i, j].type == 221 || Main.tile[i, j].type == 222 || Main.tile[i, j].type == 223 || Main.tile[i, j].type == 211 || Main.tile[i, j].type == 404)
  {
  canKillTile = false;
  }
  if (!Main.hardMode && Main.tile[i, j].type == 58)
  {
  canKillTile = false;
  }
  if (!TileLoader.CanExplode(i, j))
  {
  canKillTile = false;
  }
  if (canKillTile)
  {
  WorldGen.KillTile(i, j, false, false, false);
  if (!Main.tile[i, j].active() && Main.netMode != 0)
  {
  NetMessage.SendData(17, -1, -1, "", 0, (float)i, (float)j, 0f, 0, 0, 0);
  }
  }
  }
  if (canKillTile)
  {
  for (int x = i - 1; x <= i + 1; x++)
  {
  for (int y = j - 1; y <= j + 1; y++)
  {
  if (Main.tile[x, y] != null && Main.tile[x, y].wall > 0 && canKillWalls && WallLoader.CanExplode(x, y, Main.tile[x, y].wall))
  {
  WorldGen.KillWall(x, y, false);
  if (Main.tile[x, y].wall == 0 && Main.netMode != 0)
  {
  NetMessage.SendData(17, -1, -1, "", 2, (float)x, (float)y, 0f, 0, 0, 0);
  }
  }
  }
  }
  }
  }
  }
  }
  AchievementsHelper.CurrentlyMining = false;
  }
  }
  }
}
 
Back
Top Bottom