diff --git a/src/main/java/noppes/npcs/CommonProxy.java b/src/main/java/noppes/npcs/CommonProxy.java index 067e2f1b3..a19cb1791 100644 --- a/src/main/java/noppes/npcs/CommonProxy.java +++ b/src/main/java/noppes/npcs/CommonProxy.java @@ -17,7 +17,7 @@ import noppes.npcs.containers.*; import noppes.npcs.controllers.data.PlayerData; import noppes.npcs.entity.EntityNPCInterface; -public class CommonProxy implements IGuiHandler { +public abstract class CommonProxy implements IGuiHandler { public boolean newVersionAvailable = false; public int revision = 1; @@ -159,11 +159,13 @@ public class CommonProxy implements IGuiHandler { } - public String getAchievementDesc(Achievement achievement) { + public abstract void generateBigSmokeParticles(World world, int x, int y, int z, boolean signalFire); + + public String getAchievementDesc(Achievement achievement) { return ""; } public boolean isGUIOpen(){ return false; } -} \ No newline at end of file +} diff --git a/src/main/java/noppes/npcs/blocks/BlockCampfire.java b/src/main/java/noppes/npcs/blocks/BlockCampfire.java index a00d5fc3e..1c3cd08db 100644 --- a/src/main/java/noppes/npcs/blocks/BlockCampfire.java +++ b/src/main/java/noppes/npcs/blocks/BlockCampfire.java @@ -19,6 +19,8 @@ import org.lwjgl.opengl.GL11; import java.util.Random; +import static noppes.npcs.client.ClientProxy.RAND; + public class BlockCampfire extends BlockLightable{ public BlockCampfire(boolean lit) { @@ -88,7 +90,9 @@ public class BlockCampfire extends BlockLightable{ CustomNpcs.proxy.spawnParticle("largesmoke", d0, d1, d2, 0.0D, 0.0D, 0.0D, 2); CustomNpcs.proxy.spawnParticle("flame", d0, d1, d2, 0.0D, 0.0D, 0.0D, 4); } - + else { + tile.updateEntity(); + } GL11.glPopMatrix(); } diff --git a/src/main/java/noppes/npcs/blocks/tiles/TileCampfire.java b/src/main/java/noppes/npcs/blocks/tiles/TileCampfire.java index 178bc5d3d..e0e50f6ba 100644 --- a/src/main/java/noppes/npcs/blocks/tiles/TileCampfire.java +++ b/src/main/java/noppes/npcs/blocks/tiles/TileCampfire.java @@ -1,7 +1,58 @@ package noppes.npcs.blocks.tiles; +import noppes.npcs.CustomNpcs; + +import java.util.Random; public class TileCampfire extends TileColorable { - + + public static final Random RAND = new Random(); + private boolean rainAndSky = false; + private boolean previousTickLit = false; + + @Override + public void updateEntity() + { + if (getWorldObj().isRemote) + { + if (isLit()) + { + if (!previousTickLit || distributedInterval(50L)) + rainAndSky = isBeingRainedOn(); + + addParticles(); + } + + previousTickLit = isLit(); + } + } + + public boolean distributedInterval(long interval) + { + if (hasWorldObj()) + return (getWorldObj().getTotalWorldTime() + (long) (xCoord + yCoord + zCoord)) % interval == 0L; + else + return false; + } + + protected void addParticles() + { + CustomNpcs.proxy.generateBigSmokeParticles(getWorldObj(), xCoord, yCoord, zCoord, false); + if (rainAndSky) + { + for (int i = 0; i < RAND.nextInt(3); ++i) + getWorldObj().spawnParticle("smoke", xCoord + RAND.nextDouble(), yCoord + 0.9, zCoord + RAND.nextDouble(), 0.0, 0.0, 0.0); + } + } + public boolean isBeingRainedOn() + { + return getWorldObj().isRaining() && getWorldObj().getPrecipitationHeight(xCoord, zCoord) <= yCoord + 1 + && getWorldObj().getBiomeGenForCoords(xCoord, zCoord).canSpawnLightningBolt(); + } + + public boolean isLit() + { + return this.getBlockMetadata() == 0; + } } diff --git a/src/main/java/noppes/npcs/client/ClientProxy.java b/src/main/java/noppes/npcs/client/ClientProxy.java index b13a75387..8b511254e 100644 --- a/src/main/java/noppes/npcs/client/ClientProxy.java +++ b/src/main/java/noppes/npcs/client/ClientProxy.java @@ -6,6 +6,7 @@ import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.ObfuscationReflectionHelper; import kamkeel.addon.client.DBCClient; +import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.model.ModelBiped; @@ -32,6 +33,7 @@ import noppes.npcs.*; import noppes.npcs.api.IWorld; import noppes.npcs.blocks.tiles.*; import noppes.npcs.client.controllers.*; +import noppes.npcs.client.fx.EntityBigSmokeFX; import noppes.npcs.client.fx.EntityElementalStaffFX; import noppes.npcs.client.fx.EntityEnderFX; import noppes.npcs.client.fx.EntityRainbowFX; @@ -76,7 +78,7 @@ import java.util.Random; public class ClientProxy extends CommonProxy { public static KeyBinding NPCButton; - + public static final Random RAND = new Random(); public static FontContainer Font; public void load() { @@ -541,6 +543,17 @@ public class ClientProxy extends CommonProxy { } } + @Override + public void generateBigSmokeParticles(World world, int x, int y, int z, boolean signalFire) + { + if (RAND.nextFloat() < 0.11F) + { + float[] colours = new float[0]; + for (int i = 0; i < RAND.nextInt(2) + 1; ++i) + Minecraft.getMinecraft().effectRenderer.addEffect(new EntityBigSmokeFX(world, x, y, z, signalFire, colours)); + } + } + @Override public String getAchievementDesc(Achievement achievement) { return achievement.getDescription(); diff --git a/src/main/java/noppes/npcs/client/fx/EntityBigSmokeFX.java b/src/main/java/noppes/npcs/client/fx/EntityBigSmokeFX.java new file mode 100644 index 000000000..c645c637e --- /dev/null +++ b/src/main/java/noppes/npcs/client/fx/EntityBigSmokeFX.java @@ -0,0 +1,218 @@ +package noppes.npcs.client.fx; + +import org.lwjgl.opengl.GL11; + +import cpw.mods.fml.common.eventhandler.Cancelable; +import cpw.mods.fml.relauncher.Side; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.init.Blocks; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.EntityEvent.EntityConstructing; + +public class EntityBigSmokeFX extends EntityFX +{ + + /** there are 12 smoke textures. */ + public static final int TEXTURE_COUNT = 12; + public static final ResourceLocation[] TEXTURES = new ResourceLocation[TEXTURE_COUNT]; + static + { + for (int i = 0; i < TEXTURE_COUNT; i++) + TEXTURES[i] = new ResourceLocation("customnpcs" + ":" + "textures/particle/big_smoke_" + i + ".png"); + } + + protected final int texIndex; + protected boolean alphaFading = false; + protected float alphaFadePerTick = -0.015F; + protected boolean localizedCombustion = true; + protected boolean isColored = false; + + /** + * Posts a {@link EntityBigSmokeFXConstructingEvent}. + */ + public EntityBigSmokeFX(World world, int x, int y, int z, boolean signalFire, float[] colours) { + super(world, x, y, z); + + // Position: Centered above the spawn point with slight randomness + this.setPosition( + x + 0.5 + (rand.nextDouble() / 10.0 * (rand.nextBoolean() ? 1 : -1)), // Small horizontal offset + y + 0.1 + (rand.nextDouble() * 0.1), // Start slightly above y + z + 0.5 + (rand.nextDouble() / 10.0 * (rand.nextBoolean() ? 1 : -1)) + ); + + // Scale: Smoke size + this.particleScale = 4.0F * (rand.nextFloat() * 0.5F + 0.5F); // Smaller size + this.setSize(0.25F, 0.25F); + + // Gravity: Slows upward motion gradually + this.particleGravity = 0.005F; + + // Upward motion: Slow, with slight randomness + this.motionX = 0; // No horizontal motion + this.motionY = 0.02F + rand.nextFloat() * 0.01F; + this.motionZ = 0; // No horizontal motion + + this.particleMaxAge = rand.nextInt(50) + 100; // Shorter lifetime for normal smoke + this.particleAlpha = 0.8F; + + if (colours.length == 3) { + this.setRBGColorF(colours[0], colours[1], colours[2]); + } + + // Smoke appearance + this.texIndex = rand.nextInt(TEXTURE_COUNT); + this.isColored = this.particleRed != 1.0F || this.particleGreen != 1.0F || this.particleBlue != 1.0F; + } + + @Override + public void renderParticle(Tessellator tess, float partialTicks, float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) + { + rotX = ActiveRenderInfo.rotationX; + rotXZ = ActiveRenderInfo.rotationXZ; + rotZ = ActiveRenderInfo.rotationZ; + rotYZ = ActiveRenderInfo.rotationYZ; + rotXY = ActiveRenderInfo.rotationXY; + + EntityLivingBase view = Minecraft.getMinecraft().renderViewEntity; + double interpX = view.lastTickPosX + (view.posX - view.lastTickPosX) * partialTicks; + double interpY = view.lastTickPosY + (view.posY - view.lastTickPosY) * partialTicks; + double interpZ = view.lastTickPosZ + (view.posZ - view.lastTickPosZ) * partialTicks; + + float partialPosX = (float) (prevPosX + (posX - prevPosX) * partialTicks - interpX); + float partialPosY = (float) (prevPosY + (posY - prevPosY) * partialTicks - interpY); + float partialPosZ = (float) (prevPosZ + (posZ - prevPosZ) * partialTicks - interpZ); + + float scale = 0.1F * particleScale; + + double minU = this.particleTextureIndexX * 0.25; + double maxU = minU + 0.25; + double minV = this.particleTextureIndexY * 0.125; + double maxV = minV + 0.125; + + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); + GL11.glDepthMask(true); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F); + + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURES[this.texIndex % TEXTURES.length]); + + tess.startDrawingQuads(); + + tess.setColorRGBA_F(particleRed, particleGreen, particleBlue, particleAlpha); + tess.setBrightness(15 << 20 | 14 << 4); // slightly less than MiscUtil.MAX_LIGHT_BRIGHTNESS so that smoke doesn't glow super bright with shaders + + tess.addVertexWithUV(partialPosX - rotX * scale - rotYZ * scale, partialPosY - rotXZ * scale, partialPosZ - rotZ * scale - rotXY * scale, 1, 1); + tess.addVertexWithUV(partialPosX - rotX * scale + rotYZ * scale, partialPosY + rotXZ * scale, partialPosZ - rotZ * scale + rotXY * scale, 1, 0); + tess.addVertexWithUV(partialPosX + rotX * scale + rotYZ * scale, partialPosY + rotXZ * scale, partialPosZ + rotZ * scale + rotXY * scale, 0, 0); + tess.addVertexWithUV(partialPosX + rotX * scale - rotYZ * scale, partialPosY - rotXZ * scale, partialPosZ + rotZ * scale - rotXY * scale, 0, 1); + + tess.draw(); + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(false); + GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); + } + + @Override + public int getFXLayer() + { + return 3; + } + + @Override + public void onUpdate() { + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + + // Age-based behavior: Fade out near the end of lifetime + if (this.particleAge++ >= this.particleMaxAge - 40) { + this.alphaFading = true; + } + + if (this.particleAge < this.particleMaxAge && this.particleAlpha > 0.0F) { + // Minimal horizontal drift for slight randomness + float horizontalMotionScale = 0.001F; // Very small horizontal movement + this.motionX += this.rand.nextFloat() * horizontalMotionScale * (this.rand.nextBoolean() ? 1 : -1); + this.motionZ += this.rand.nextFloat() * horizontalMotionScale * (this.rand.nextBoolean() ? 1 : -1); + + // Move the particle + this.moveEntity(this.motionX, this.motionY, this.motionZ); + + // Fade out alpha if needed + if (this.alphaFading) { + this.particleAlpha = MathHelper.clamp_float(this.particleAlpha + this.alphaFadePerTick, 0.0F, 1.0F); + } + } else { + // Kill the particle if it has faded out or reached max age + this.setDead(); + } + } + + + + /** + * Allows you to change various aspects of campfire smoke particles:
+ * - {@link #particleRed}, {@link #particleGreen}, and {@link #particleBlue} are the float r, g, b values of the smoke.
+ * - {@link #motionX}, {@link #motionY}, and {@link #motionZ} are the x, y, z motion of the smoke.
+ * - {@link #particleGravity} is the amount the smoke's y motion changes per tick.
+ * - {@link #particleAlpha} is the smoke's initial alpha.
+ * - {@link #alphaFading} is whether the smoke's alpha should currently be changing (fading in or out).
+ * - {@link #alphaFadePerTick} is the amount the smoke's alpha changes per tick if {@link #alphaFading} is true. Negative values make it fade out, positive values make it fade + * back in.
+ * - {@link #particleMaxAge} is the maximum number of ticks the particle will live for.
+ *
+ * You're also given {@link #campfirePosition}, which is the x, y, z position of the campfire tile entity where the smoke was created.
+ *
+ * Also, {@link EntityBigSmokeFX} are only created on the client side, so you should mark your subscribe event with {@link Side#CLIENT}.
+ *
+ * This event is posted from {@link EntityBigSmokeFX#EntityBigSmokeFX} on the {@link MinecraftForge#EVENT_BUS}.
+ * This event is {@link Cancelable}. If canceled, the entity will be removed.
+ */ + @Cancelable + public static class EntityBigSmokeFXConstructingEvent extends EntityConstructing + { + public final int[] campfirePosition; + + public float particleRed; + public float particleGreen; + public float particleBlue; + public double motionX; + public double motionY; + public double motionZ; + public float particleGravity; + public float particleAlpha; + public boolean alphaFading; + public float alphaFadePerTick; + public int particleMaxAge; + + public EntityBigSmokeFXConstructingEvent(EntityBigSmokeFX entity, int x, int y, int z) + { + super(entity); + + campfirePosition = new int[] { x, y, z }; + + particleRed = entity.particleRed; + particleGreen = entity.particleGreen; + particleBlue = entity.particleBlue; + motionX = entity.motionX; + motionY = entity.motionY; + motionZ = entity.motionZ; + particleGravity = entity.particleGravity; + particleAlpha = entity.particleAlpha; + alphaFading = entity.alphaFading; + alphaFadePerTick = entity.alphaFadePerTick; + particleMaxAge = entity.particleMaxAge; + } + + } + +} diff --git a/src/main/java/noppes/npcs/client/model/blocks/campfire/ModelCampfireCoals.java b/src/main/java/noppes/npcs/client/model/blocks/campfire/ModelCampfireCoals.java new file mode 100644 index 000000000..9f10ef8c9 --- /dev/null +++ b/src/main/java/noppes/npcs/client/model/blocks/campfire/ModelCampfireCoals.java @@ -0,0 +1,30 @@ +package noppes.npcs.client.model.blocks.campfire; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; + +public class ModelCampfireCoals extends ModelBase { + private final ModelRenderer bb_main; + + public ModelCampfireCoals() { + textureWidth = 64; + textureHeight = 64; + + bb_main = new ModelRenderer(this); + bb_main.setRotationPoint(0.0F, 24.0F, 0.0F); + bb_main.cubeList.add(new ModelBox(bb_main, -10, 0, -5.0F, -0.02F, -5.0F, 10, 0, 10, 0.0F)); + } + + @Override + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { + bb_main.render(f5); + } + + public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) { + modelRenderer.rotateAngleX = x; + modelRenderer.rotateAngleY = y; + modelRenderer.rotateAngleZ = z; + } +} diff --git a/src/main/java/noppes/npcs/client/model/blocks/campfire/ModelCampfireLog.java b/src/main/java/noppes/npcs/client/model/blocks/campfire/ModelCampfireLog.java index 20acf6bfc..414fff49b 100644 --- a/src/main/java/noppes/npcs/client/model/blocks/campfire/ModelCampfireLog.java +++ b/src/main/java/noppes/npcs/client/model/blocks/campfire/ModelCampfireLog.java @@ -6,46 +6,46 @@ import net.minecraft.client.model.ModelRenderer; import net.minecraft.entity.Entity; public class ModelCampfireLog extends ModelBase { - private final ModelRenderer bb_main; - private final ModelRenderer cube_r1; - private final ModelRenderer cube_r2; - private final ModelRenderer cube_r3; + private final ModelRenderer bb_main; + private final ModelRenderer cube_r1; + private final ModelRenderer cube_r2; + private final ModelRenderer cube_r3; - public ModelCampfireLog() { - textureWidth = 16; - textureHeight = 16; + public ModelCampfireLog() { + textureWidth = 16; + textureHeight = 16; - bb_main = new ModelRenderer(this); - bb_main.setRotationPoint(0.0F, 24.0F, 0.0F); + bb_main = new ModelRenderer(this); + bb_main.setRotationPoint(0.0F, 24.0F, 0.0F); - cube_r1 = new ModelRenderer(this); - cube_r1.setRotationPoint(1.25F, -6.3F, 1.25F); - bb_main.addChild(cube_r1); - setRotationAngle(cube_r1, 0.5449F, -1.0854F, -0.744F); - cube_r1.cubeList.add(new ModelBox(cube_r1, 0, 0, -1.0F, -4.0F, -1.0F, 3, 10, 3, 0.0F)); + cube_r1 = new ModelRenderer(this); + cube_r1.setRotationPoint(1.25F, -6.3F, 1.25F); + bb_main.addChild(cube_r1); + setRotationAngle(cube_r1, 0.5449F, -1.0854F, -0.744F); + cube_r1.cubeList.add(new ModelBox(cube_r1, 0, 0, -1.0F, -2.0F, -1.0F, 3, 8, 3, 0.0F)); - cube_r2 = new ModelRenderer(this); - cube_r2.setRotationPoint(-1.5F, -6.0F, -0.25F); - bb_main.addChild(cube_r2); - setRotationAngle(cube_r2, 0.0F, 0.0F, 0.3927F); - cube_r2.cubeList.add(new ModelBox(cube_r2, 0, 0, -2.0F, -4.0F, -1.0F, 3, 10, 3, 0.0F)); + cube_r2 = new ModelRenderer(this); + cube_r2.setRotationPoint(-1.5F, -6.0F, -0.25F); + bb_main.addChild(cube_r2); + setRotationAngle(cube_r2, 0.0F, 0.0F, 0.3927F); + cube_r2.cubeList.add(new ModelBox(cube_r2, 0, 0, -2.0F, -2.0F, -1.0F, 3, 8, 3, 0.0F)); - cube_r3 = new ModelRenderer(this); - cube_r3.setRotationPoint(1.5F, -6.0F, -2.25F); - bb_main.addChild(cube_r3); - setRotationAngle(cube_r3, -0.3295F, 0.7268F, -0.4754F); - cube_r3.cubeList.add(new ModelBox(cube_r3, 0, 0, -2.0F, -4.5F, -1.0F, 3, 10, 3, 0.0F)); - } + cube_r3 = new ModelRenderer(this); + cube_r3.setRotationPoint(1.5F, -6.0F, -2.25F); + bb_main.addChild(cube_r3); + setRotationAngle(cube_r3, -0.3295F, 0.7268F, -0.4754F); + cube_r3.cubeList.add(new ModelBox(cube_r3, 0, 0, -2.0F, -2.5F, -1.0F, 3, 8, 3, 0.0F)); + } - @Override - public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { - bb_main.render(f5); - } + @Override + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { + bb_main.render(f5); + } - public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) { - modelRenderer.rotateAngleX = x; - modelRenderer.rotateAngleY = y; - modelRenderer.rotateAngleZ = z; - } + public void setRotationAngle(ModelRenderer modelRenderer, float x, float y, float z) { + modelRenderer.rotateAngleX = x; + modelRenderer.rotateAngleY = y; + modelRenderer.rotateAngleZ = z; + } } diff --git a/src/main/java/noppes/npcs/client/renderer/blocks/BlockCampfireRenderer.java b/src/main/java/noppes/npcs/client/renderer/blocks/BlockCampfireRenderer.java index 5e51f1d49..9b98638d1 100644 --- a/src/main/java/noppes/npcs/client/renderer/blocks/BlockCampfireRenderer.java +++ b/src/main/java/noppes/npcs/client/renderer/blocks/BlockCampfireRenderer.java @@ -5,11 +5,13 @@ import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.IBlockAccess; import noppes.npcs.CustomItems; import noppes.npcs.blocks.BlockRotated; import noppes.npcs.blocks.tiles.TileColorable; import noppes.npcs.client.model.blocks.ModelCampfire; +import noppes.npcs.client.model.blocks.campfire.ModelCampfireCoals; import noppes.npcs.client.model.blocks.campfire.ModelCampfireFlame; import noppes.npcs.client.model.blocks.campfire.ModelCampfireLog; import noppes.npcs.client.model.blocks.campfire.ModelCampfireStone; @@ -26,7 +28,9 @@ public class BlockCampfireRenderer extends BlockRendererInterface{ private final ModelCampfireFlame flameModel = new ModelCampfireFlame(); private final ModelCampfireLog logsModel = new ModelCampfireLog(); private final ModelCampfireStone stonesModel = new ModelCampfireStone(); + private final ModelCampfireCoals coalsModel = new ModelCampfireCoals(); + protected static final ResourceLocation coalsTexture = new ResourceLocation("customnpcs","textures/models/CampfireCoals.png"); public BlockCampfireRenderer(){ ((BlockRotated)CustomItems.campfire).renderId = RenderingRegistry.getNextAvailableRenderId(); @@ -60,9 +64,15 @@ public class BlockCampfireRenderer extends BlockRendererInterface{ Minecraft.getMinecraft().getTextureManager().bindTexture(Cobble); stonesModel.render(null, 0, 0, 0, 0, 0.0F, 0.0625F); if(block == CustomItems.campfire){ + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_ALPHA_TEST); Minecraft.getMinecraft().getTextureManager().bindTexture(Flame); flameModel.render(null, tile.getWorldObj().getWorldTime(), 0, 0, 0, 0.0F, 0.0625F); + GL11.glDisable(GL11.GL_ALPHA_TEST); + GL11.glEnable(GL11.GL_LIGHTING); } + Minecraft.getMinecraft().getTextureManager().bindTexture(coalsTexture); + coalsModel.render(null, 0, 0, 0, 0, 0.0F, 0.0625F); } GL11.glPopMatrix(); diff --git a/src/main/resources/assets/customnpcs/textures/models/CampfireCoals.png b/src/main/resources/assets/customnpcs/textures/models/CampfireCoals.png new file mode 100644 index 000000000..f2732b51b Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/models/CampfireCoals.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_0.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_0.png new file mode 100644 index 000000000..727f1d6a5 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_0.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_1.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_1.png new file mode 100644 index 000000000..8c07ee3b0 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_1.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_10.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_10.png new file mode 100644 index 000000000..712c41cb1 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_10.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_11.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_11.png new file mode 100644 index 000000000..7f3a7dbd2 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_11.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_2.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_2.png new file mode 100644 index 000000000..81d1a98cd Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_2.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_3.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_3.png new file mode 100644 index 000000000..4a5f8224d Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_3.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_4.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_4.png new file mode 100644 index 000000000..17c35e5a7 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_4.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_5.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_5.png new file mode 100644 index 000000000..3dbb32af4 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_5.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_6.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_6.png new file mode 100644 index 000000000..1e5fec17e Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_6.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_7.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_7.png new file mode 100644 index 000000000..ebef40c2a Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_7.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_8.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_8.png new file mode 100644 index 000000000..a704e860a Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_8.png differ diff --git a/src/main/resources/assets/customnpcs/textures/particle/big_smoke_9.png b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_9.png new file mode 100644 index 000000000..4dd14f324 Binary files /dev/null and b/src/main/resources/assets/customnpcs/textures/particle/big_smoke_9.png differ