diff --git a/src/main/java/electroblob/wizardry/CommonProxy.java b/src/main/java/electroblob/wizardry/CommonProxy.java index 367352c7..846d65ab 100644 --- a/src/main/java/electroblob/wizardry/CommonProxy.java +++ b/src/main/java/electroblob/wizardry/CommonProxy.java @@ -70,8 +70,6 @@ public class CommonProxy { public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, IBlockState block, BlockPos pos){ } - - public void spawnEntityParticle(World world, Entity entity, int maxAge, float r, float g, float b){} // SECTION Items // =============================================================================================================== diff --git a/src/main/java/electroblob/wizardry/WizardryEventHandler.java b/src/main/java/electroblob/wizardry/WizardryEventHandler.java index a46d2730..f5ea91ac 100644 --- a/src/main/java/electroblob/wizardry/WizardryEventHandler.java +++ b/src/main/java/electroblob/wizardry/WizardryEventHandler.java @@ -206,22 +206,13 @@ public final class WizardryEventHandler { // Static Aura if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura)){ - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(event.getEntityLiving().posX, event.getEntityLiving().posY + 1, - event.getEntityLiving().posZ, attacker.posX, attacker.posY + attacker.height / 2, - attacker.posZ); - world.spawnEntity(arc); - }else{ - for(int i = 0; i < 8; i++){ - ParticleBuilder.create(Type.SPARK).pos(attacker.posX + world.rand.nextFloat() - 0.5, - attacker.getEntityBoundingBox().minY + attacker.height / 2 + world.rand.nextFloat() * 2 - 1, - attacker.posZ + world.rand.nextFloat() - 0.5).spawn(world); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, attacker.posX + world.rand.nextFloat() - 0.5, - attacker.getEntityBoundingBox().minY + attacker.height / 2 + world.rand.nextFloat() * 2 - - 1, - attacker.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); - } + if(world.isRemote){ + + ParticleBuilder.create(Type.LIGHTNING).entity(event.getEntity()).pos(0, event.getEntity().height/2, 0) + .target(attacker).spawn(world); + + ParticleBuilder.spawnShockParticles(world, attacker.posX, + attacker.getEntityBoundingBox().minY + attacker.height, attacker.posZ); } attacker.attackEntityFrom( diff --git a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java index 27bc7046..a10aa77e 100644 --- a/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java +++ b/src/main/java/electroblob/wizardry/block/BlockCrystalFlower.java @@ -43,7 +43,7 @@ public class BlockCrystalFlower extends BlockBush { if(world.isRemote && random.nextBoolean()){ ParticleBuilder.create(Type.SPARKLE) .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble() / 2 + 0.5, pos.getZ() + random.nextDouble()).vel(0, 0.01, 0) - .lifetime(20 + random.nextInt(10)).colour(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), + .time(20 + random.nextInt(10)).clr(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/block/BlockSpectral.java b/src/main/java/electroblob/wizardry/block/BlockSpectral.java index 708f3fe6..07023985 100644 --- a/src/main/java/electroblob/wizardry/block/BlockSpectral.java +++ b/src/main/java/electroblob/wizardry/block/BlockSpectral.java @@ -70,9 +70,9 @@ public class BlockSpectral extends BlockContainer { // Top surface for(int i=0; i<2; i++){ ParticleBuilder.create(Type.DUST) - .pos(pos.getX() + random.nextDouble(), pos.getY() + 1, pos.getZ() + random.nextDouble()) - .lifetime((int)(16.0D / (Math.random() * 0.8D + 0.2D))) - .colour(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f) + .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble()) + .time((int)(16.0D / (Math.random() * 0.8D + 0.2D))) + .clr(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f) .shaded(true).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/client/ClientProxy.java b/src/main/java/electroblob/wizardry/client/ClientProxy.java index d688d89f..82630f2d 100644 --- a/src/main/java/electroblob/wizardry/client/ClientProxy.java +++ b/src/main/java/electroblob/wizardry/client/ClientProxy.java @@ -13,25 +13,9 @@ import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.gui.GuiSpellDisplay; import electroblob.wizardry.client.gui.GuiWizardHandbook; import electroblob.wizardry.client.model.ModelWizardArmour; -import electroblob.wizardry.client.particle.ParticleBlizzard; -import electroblob.wizardry.client.particle.ParticleBuff; -import electroblob.wizardry.client.particle.ParticleDarkMagic; -import electroblob.wizardry.client.particle.ParticleDust; -import electroblob.wizardry.client.particle.ParticleFlash; -import electroblob.wizardry.client.particle.ParticleIce; -import electroblob.wizardry.client.particle.ParticleLeaf; -import electroblob.wizardry.client.particle.ParticleMagicBubble; -import electroblob.wizardry.client.particle.ParticleMagicFlame; -import electroblob.wizardry.client.particle.ParticlePath; -import electroblob.wizardry.client.particle.ParticleRotatingSparkle; -import electroblob.wizardry.client.particle.ParticleSnow; -import electroblob.wizardry.client.particle.ParticleSpark; -import electroblob.wizardry.client.particle.ParticleSparkle; -import electroblob.wizardry.client.particle.ParticleTornado; -import electroblob.wizardry.client.particle.ParticleWizardry; +import electroblob.wizardry.client.particle.*; import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory; import electroblob.wizardry.client.renderer.LayerStone; -import electroblob.wizardry.client.renderer.RenderArc; import electroblob.wizardry.client.renderer.RenderArcaneWorkbench; import electroblob.wizardry.client.renderer.RenderBlackHole; import electroblob.wizardry.client.renderer.RenderBlank; @@ -45,7 +29,6 @@ import electroblob.wizardry.client.renderer.RenderHammer; import electroblob.wizardry.client.renderer.RenderIceGiant; import electroblob.wizardry.client.renderer.RenderIceSpike; import electroblob.wizardry.client.renderer.RenderLightningDisc; -import electroblob.wizardry.client.renderer.RenderLightningPulse; import electroblob.wizardry.client.renderer.RenderMagicArrow; import electroblob.wizardry.client.renderer.RenderMagicLight; import electroblob.wizardry.client.renderer.RenderPhoenix; @@ -55,7 +38,6 @@ import electroblob.wizardry.client.renderer.RenderSpiritHorse; import electroblob.wizardry.client.renderer.RenderSpiritWolf; import electroblob.wizardry.client.renderer.RenderStatue; import electroblob.wizardry.client.renderer.RenderWizard; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.entity.EntityShield; import electroblob.wizardry.entity.construct.EntityArrowRain; import electroblob.wizardry.entity.construct.EntityBlackHole; @@ -71,7 +53,6 @@ import electroblob.wizardry.entity.construct.EntityHailstorm; import electroblob.wizardry.entity.construct.EntityHammer; import electroblob.wizardry.entity.construct.EntityHealAura; import electroblob.wizardry.entity.construct.EntityIceSpike; -import electroblob.wizardry.entity.construct.EntityLightningPulse; import electroblob.wizardry.entity.construct.EntityLightningSigil; import electroblob.wizardry.entity.construct.EntityTornado; import electroblob.wizardry.entity.living.EntityDecoy; @@ -291,27 +272,30 @@ public class ClientProxy extends CommonProxy { public void initParticleFactories(){ factories = new HashMap<>(); - - factories.put(Type.BLIZZARD, (world, x, y, z) -> new ParticleBlizzard(world, x, y, z)); - factories.put(Type.DARK_MAGIC, (world, x, y, z) -> new ParticleDarkMagic(world, x, y, z)); - factories.put(Type.DUST, (world, x, y, z) -> new ParticleDust(world, x, y, z)); - factories.put(Type.FLASH, (world, x, y, z) -> new ParticleFlash(world, x, y, z)); - factories.put(Type.ICE, (world, x, y, z) -> new ParticleIce(world, x, y, z)); - factories.put(Type.LEAF, (world, x, y, z) -> new ParticleLeaf(world, x, y, z)); - factories.put(Type.MAGIC_BUBBLE, (world, x, y, z) -> new ParticleMagicBubble(world, x, y, z)); - factories.put(Type.MAGIC_FIRE, (world, x, y, z) -> new ParticleMagicFlame(world, x, y, z)); - factories.put(Type.PATH, (world, x, y, z) -> new ParticlePath(world, x, y, z)); - factories.put(Type.SNOW, (world, x, y, z) -> new ParticleSnow(world, x, y, z)); - factories.put(Type.SPARK, (world, x, y, z) -> new ParticleSpark(world, x, y, z)); - factories.put(Type.SPARKLE, (world, x, y, z) -> new ParticleSparkle(world, x, y, z)); - factories.put(Type.SPARKLE_ROTATING, (world, x, y, z) -> new ParticleRotatingSparkle(world, x, y, z)); + + factories.put(Type.BEAM, ParticleBeam::new); + factories.put(Type.BUFF, ParticleBuff::new); + factories.put(Type.DARK_MAGIC, ParticleDarkMagic::new); + factories.put(Type.DUST, ParticleDust::new); + factories.put(Type.FLASH, ParticleFlash::new); + factories.put(Type.ICE, ParticleIce::new); + factories.put(Type.LEAF, ParticleLeaf::new); + factories.put(Type.LIGHTNING, ParticleLightning::new); + factories.put(Type.LIGHTNING_PULSE, ParticleLightningPulse::new); + factories.put(Type.MAGIC_BUBBLE, ParticleMagicBubble::new); + factories.put(Type.MAGIC_FIRE, ParticleMagicFlame::new); + factories.put(Type.PATH, ParticlePath::new); + factories.put(Type.SCORCH, ParticleScorch::new); + factories.put(Type.SNOW, ParticleSnow::new); + factories.put(Type.SPARK, ParticleSpark::new); + factories.put(Type.SPARKLE, ParticleSparkle::new); } @Override public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){ IWizardryParticleFactory factory = factories.get(type); if(factory == null){ - Wizardry.logger.warn("Unrecognised particle type %s! Ensure the particle is properly registered.", type); + Wizardry.logger.warn("Unrecognised particle type %s ! Ensure the particle is properly registered.", type); return null; } return factory.createParticle(world, x, y, z); @@ -431,8 +415,8 @@ public class ClientProxy extends CommonProxy { double x = caster.posX + radius * Math.cos(angle); double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2; double z = caster.posZ + radius * Math.sin(angle); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).colour(0.6f, 1, 0.6f) - .lifetime(80 + world.rand.nextInt(10)).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).clr(0.6f, 1, 0.6f) + .time(80 + world.rand.nextInt(10)).spawn(world); } for(int i = 0; i < 20; i++){ double radius = 1; @@ -578,7 +562,6 @@ public class ClientProxy extends CommonProxy { manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/smoke_bomb.png"), false)); // Effects and constructs - RenderingRegistry.registerEntityRenderingHandler(EntityArc.class, RenderArc::new); RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new); RenderingRegistry.registerEntityRenderingHandler(EntityShield.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new); @@ -608,7 +591,6 @@ public class ClientProxy extends CommonProxy { RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class, manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f)); RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new); - RenderingRegistry.registerEntityRenderingHandler(EntityLightningPulse.class, manager -> new RenderLightningPulse(manager, 8.0f)); // TESRs ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench()); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java new file mode 100644 index 00000000..63548e0b --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBeam.java @@ -0,0 +1,95 @@ +package electroblob.wizardry.client.particle; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.world.World; + +public class ParticleBeam extends ParticleTargeted { + + /** Half the width of the outermost layer. */ + private static final float THICKNESS = 0.1f; + + public ParticleBeam(World world, double x, double y, double z){ + super(world, x, y, z); // Does not have a texture! + this.setRBGColorF(1, 1, 1); + this.setMaxAge(1); + this.particleScale = 1; + } + + @Override + public int getFXLayer(){ + return 3; + } + + @Override + protected void draw(Tessellator tessellator, double length, float partialTicks){ + + float scale = this.particleScale; + + if(this.particleMaxAge > 1){ + float ageFraction = (particleAge + partialTicks - 1)/particleMaxAge; + // Squaring this makes it look smoother than a linear shrinking effect + scale = this.particleScale * (1 - ageFraction*ageFraction); + } + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + for(int layer=0; layer<3; layer++){ + drawSegment(tessellator, layer, 0, 0, 0, 0, 0, length, THICKNESS * scale); + } + + GlStateManager.enableTexture2D(); + GlStateManager.enableLighting(); + GlStateManager.disableBlend(); + } + + /** Draws the given layer of a segment of the arc, from the point (x1, y1, z1) to the point (x2, y2, z2), with the given thickness. */ + private void drawSegment(Tessellator tessellator, int layer, double x1, double y1, double z1, double x2, double y2, double z2, float thickness){ + + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_COLOR); + + switch(layer){ + + case 0: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.25f*thickness, 1, 1, 1, 1); + break; + + case 1: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.6f*thickness, (particleRed + 1)/2, (particleGreen + 1)/2, + (particleBlue + 1)/2, 0.65f); + break; + + case 2: + drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, thickness, particleRed, particleGreen, particleBlue, 0.3f); + break; + } + + tessellator.draw(); + } + + /** Draws a single box for one segment of the arc, from the point (x1, y1, z1) to the point (x2, y2, z2), with given width and colour. */ + private void drawShearedBox(BufferBuilder buffer, double x1, double y1, double z1, double x2, double y2, double z2, float width, float r, float g, float b, float a){ + + buffer.pos(x1-width, y1-width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2-width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1-width, y1+width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2+width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1+width, y1+width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2+width, y2+width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1+width, y1-width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2+width, y2-width, z2).color(r, g, b, a).endVertex(); + buffer.pos(x1-width, y1-width, z1).color(r, g, b, a).endVertex(); + buffer.pos(x2-width, y2-width, z2).color(r, g, b, a).endVertex(); + } + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java deleted file mode 100644 index 9f7c2828..00000000 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleBlizzard.java +++ /dev/null @@ -1,67 +0,0 @@ -package electroblob.wizardry.client.particle; - -import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -@SideOnly(Side.CLIENT) -public class ParticleBlizzard extends ParticleSnow { - - private double angle; - private double radius; - private double speed; - - public ParticleBlizzard(World world, double ox, double y, double oz){ - super(world, ox, y, oz); - this.angle = this.rand.nextDouble() * Math.PI * 2; - double x = ox - Math.cos(angle) * radius; - double z = oz + radius * Math.sin(angle); - this.setPosition(x, y, z); - this.prevPosX = x; - this.prevPosY = y; - this.prevPosZ = z; - if(rand.nextBoolean()){ - speed = rand.nextDouble() * 2 + 1; - }else{ - speed = rand.nextDouble() * -2 - 1; - } - this.multipleParticleScaleBy(1.5f); - } - - // @Override - // public void renderParticle(VertexBuffer buffer, Entity entity, float partialTicks, float rotationX, float - // rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ - // if(this.particleAge < this.particleMaxAge / 3 || (this.particleAge + this.particleMaxAge) / 3 % 2 == 0){ - // super.renderParticle(buffer, entity, partialTicks, rotationX, rotationZ, rotationYZ, rotationXY, rotationXZ); - // } - // } - - @Override - public void onUpdate(){ - - this.prevPosX = this.posX; - this.prevPosY = this.posY; - this.prevPosZ = this.posZ; - - if(this.particleAge++ >= this.particleMaxAge){ - this.setExpired(); - } - - // This is in radians per tick... - double omega = Math.signum(speed) * ((Math.PI * 2) / 20 - speed / (20 * radius)); - - // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. - this.angle += omega; - - this.motionY -= 0.04D * (double)this.particleGravity; - this.motionZ = radius * omega * Math.cos(angle); - this.motionX = radius * omega * Math.sin(angle); - this.move(motionX, motionY, motionZ); - - if(this.particleAge > this.particleMaxAge / 2){ - this.setAlphaF( - 1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); - } - - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java index b7ea5432..9e9a46d0 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleBuff.java @@ -21,36 +21,41 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleBuff extends ParticleEntityLinked { +public class ParticleBuff extends ParticleWizardry { private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png"); private final boolean mirror; - public ParticleBuff(World world, Entity entity, float r, float g, float b, boolean mirror){ - super(world, entity); - this.setRBGColorF(r, g, b); - this.mirror = mirror; - } - - public ParticleBuff(World world, Entity entity, int maxAge, float r, float g, float b, boolean mirror){ - super(world, entity, maxAge); - this.setRBGColorF(r, g, b); - this.mirror = mirror; - } - - @Override - public void init(){ - this.particleGravity = 0; - this.posY += 1; + public ParticleBuff(World world, double x, double y, double z){ + super(world, x, y, z); + this.setVelocity(0, 0.27, 0); // Approximately what it was before + this.mirror = world.rand.nextBoolean(); + this.setMaxAge(15); + this.setGravity(false); + this.canCollide = false; } @Override public void onUpdate(){ super.onUpdate(); - this.setPosition(this.entity.posX, this.entity.posY + 1 + 4f * this.particleAge/this.particleMaxAge, this.entity.posZ); if(this.particleAge > this.particleMaxAge/2) this.particleAlpha = 2f - 2f*(float)this.particleAge/(float)this.particleMaxAge; } + /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png + * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the + * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine + * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was + * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning + * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten + * anyway since they bind their own textures. It is of course important to bind the texture every time you render a + * custom particle, but I don't see how you could do it any other way, since you don't have access to + * EffectRenderer. */ + @Override + public int getFXLayer(){ + // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. + return 3; + } + @Override public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java b/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java deleted file mode 100644 index fadf37d9..00000000 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleCustomTexture.java +++ /dev/null @@ -1,130 +0,0 @@ -package electroblob.wizardry.client.particle; - -import org.lwjgl.opengl.GL11; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.entity.Entity; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.World; - -@Deprecated -public abstract class ParticleCustomTexture extends ParticleWizardry { - - public ParticleCustomTexture(World world, double x, double y, double z){ - super(world, x, y, z); - } - - /** - * Returns a ResourceLocation for the particle's texture sheet. Do not create a new ResourceLocation in this method, - * only return a constant. - */ - public abstract ResourceLocation getTexture(); - - /** Returns how many 'frames' there are in the x direction on the texture. */ - protected abstract int getXFrames(); - - /** Returns how many 'frames' there are in the y direction on the texture. */ - protected abstract int getYFrames(); - - /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png - * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the - * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine - * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was - * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning - * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten - * anyway since they bind their own textures. It is of course important to bind the texture every time you render a - * custom particle, but I don't see how you could do it any other way, since you don't have access to - * EffectRenderer. */ - @Override - public int getFXLayer(){ - // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. - return 3; - } - - @Override - public void setParticleTextureIndex(int index){ - this.particleTextureIndexX = index % getXFrames(); - this.particleTextureIndexY = index / getYFrames(); - } - - // Overridden to bind the new texture. I think this can be done with TextureAtlasSprite, but this works as it is - // so I'm not changing it for the time being. - @Override - public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, - float rotationYZ, float rotationXY, float rotationXZ){ - - GlStateManager.pushMatrix(); - - this.applyGLStateChanges(); - - // This stuff does the shading. It vanilla does this later on for each point, but this also seems to work. - int brightness = this.getBrightnessForRender(partialTicks); - int lightmapX = brightness % 65536; - int lightmapY = brightness / 65536; - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)lightmapX / 1.0F, - (float)lightmapY / 1.0F); - - RenderHelper.disableStandardItemLighting(); - - Minecraft.getMinecraft().getTextureManager().bindTexture(getTexture()); - - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); - - float u1 = (float)this.particleTextureIndexX / (float)getXFrames(); - float u2 = u1 + 1.0f / getXFrames(); - float v1 = (float)this.particleTextureIndexY / (float)getYFrames(); - float v2 = v1 + 1.0f / getYFrames(); - float scale = 0.1F * this.particleScale; - - // I'm pretty sure these were always static. - Particle.interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks; - Particle.interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks; - Particle.interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks; - - float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); - float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); - float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); - - buffer.pos((double)(x - rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), - (double)(z - rotationYZ * scale - rotationXZ * scale)).tex(u2, v2) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos((double)(x - rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), - (double)(z - rotationYZ * scale + rotationXZ * scale)).tex(u2, v1) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos((double)(x + rotationX * scale + rotationXY * scale), (double)(y + rotationZ * scale), - (double)(z + rotationYZ * scale + rotationXZ * scale)).tex(u1, v1) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - buffer.pos((double)(x + rotationX * scale - rotationXY * scale), (double)(y - rotationZ * scale), - (double)(z + rotationYZ * scale - rotationXZ * scale)).tex(u1, v2) - .color(particleRed, particleGreen, particleBlue, particleAlpha).endVertex(); - ; - - Tessellator.getInstance().draw(); - - this.undoGLStateChanges(); - - GlStateManager.popMatrix(); - - } - - /** - * Override to add any GL state changes, like blending. Does nothing by default. State changes should be done - * using GLStateManager, not using GL11 directly (as is the case with all rendering code now). - */ - public void applyGLStateChanges(){ - } - - /** - * Override to undo any GL state changes, like blending. Does nothing by default. State changes should be done - * using GLStateManager, not using GL11 directly (as is the case with all rendering code now). - */ - public void undoGLStateChanges(){ - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java b/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java deleted file mode 100644 index 76dfaefb..00000000 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleEntityLinked.java +++ /dev/null @@ -1,61 +0,0 @@ -package electroblob.wizardry.client.particle; - -import net.minecraft.client.particle.Particle; -import net.minecraft.entity.Entity; -import net.minecraft.world.World; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -/** - * Abstract superclass for particles that are linked to entities, i.e. move with a given entity. This is generally used - * for visual effects in spell casting. - * - * @author Electroblob - * @since Wizardry 4.2 - */ -@SideOnly(Side.CLIENT) -public abstract class ParticleEntityLinked extends Particle { - - /** True if the particle always renders at full brightness. Defaults to false. */ - protected boolean fullBrightness = false; - - /** The entity this particle is linked to. The particle will move with this entity. */ - protected Entity entity; - - public ParticleEntityLinked(World world, Entity entity){ - super(world, entity.posX, entity.posY, entity.posZ, entity.motionX, entity.motionY, entity.motionZ); - this.entity = entity; - this.init(); - } - - public ParticleEntityLinked(World world, Entity entity, int maxAge){ - this(world, entity); - this.particleMaxAge = maxAge; - } - - /** - * Called from both constructors to set constants, avoiding duplicate code. Common fields to set here include: - * particleScale, particleGravity, canCollide, fullBrightness and setting the texture index. - */ - public abstract void init(); - - /* There are 4 layers of particles, specified as 0-3 by the method below. - Layer 0 causes the normal particles.png - * to be bound to the render engine for normal particles. - Layer 1 causes the block textures to be bound to the - * render engine for digging fx and falling fx. - Layer 2 causes the item textures to be bound to the render engine - * for tool breaking fx, snowballpoofs, slime particles, etc. - Layer 3 is not used in vanilla minecraft and was - * presumably added by forge for exactly this reason. This means no texture is bound by vanilla minecraft, meaning - * you are free to do as you wish without possibly overwriting vanilla particles. Mod particles won't be overwritten - * anyway since they bind their own textures. It is of course important to bind the texture every time you render a - * custom particle, but I don't see how you could do it any other way, since you don't have access to - * EffectRenderer. */ - @Override - public int getFXLayer(){ - // This can only be 0-3 or it will cause an ArrayIndexOutOfBoundsException in EffectRenderer. - return 3; - } - - @Override - public int getBrightnessForRender(float partialTick){ - return fullBrightness ? 15728880 : super.getBrightnessForRender(partialTick); - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java index 0e23c95f..a24cd16b 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleFlash.java @@ -17,13 +17,13 @@ public class ParticleFlash extends ParticleWizardry { super(world, x, y, z); this.setRBGColorF(1, 1, 1); this.particleScale = 0.6f; // 7.1f is the value used in fireworks - this.particleMaxAge = 4; + this.particleMaxAge = 6; } @Override public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ - float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F) * 0.25F * (float)Math.PI); - this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F) * 0.25F * 0.5F); + float f4 = particleScale * MathHelper.sin(((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * (float)Math.PI); + this.setAlphaF(0.6F - ((float)this.particleAge + partialTicks - 1.0F)/particleMaxAge * 0.5F); float f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java index 7c703f7c..bc530448 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleIce.java @@ -1,40 +1,36 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleIce extends ParticleCustomTexture { - - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/ice_particles.png"); +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleIce extends ParticleWizardry { + private static final ResourceLocation[] TEXTURES = generateTextures("ice", 8); + public ParticleIce(World world, double x, double y, double z){ - super(world, x, y, z); - this.setParticleTextureIndex(rand.nextInt(8)); + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.canCollide = true; // Defaults + this.setRBGColorF(1, 1, 1); this.particleScale *= 0.75f; this.setGravity(true); this.shaded = false; } - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java index dbfab7a5..327ac57a 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLeaf.java @@ -1,41 +1,47 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleLeaf extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleLeaf extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/leaf_particles.png"); + private static final ResourceLocation[] TEXTURES = generateTextures("leaf", 16); public ParticleLeaf(World world, double x, double y, double z){ - super(world, x, y, z); + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.setVelocity(0, -0.03, 0); - this.setLifetime(10 + rand.nextInt(5)); - this.setParticleTextureIndex(rand.nextInt(16)); + this.setMaxAge(10 + rand.nextInt(5)); this.particleScale *= 1.4f; this.particleGravity = 0; this.canCollide = true; // Produces a variety of browns and greens this.setRBGColorF(0.1f + 0.3f * world.rand.nextFloat(), 0.5f + 0.3f * world.rand.nextFloat(), 0.1f); } - + @Override - public ResourceLocation getTexture(){ - return TEXTURE; + public void onUpdate(){ + + super.onUpdate(); + + // Fading + if(this.particleAge > this.particleMaxAge / 2){ + this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java b/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java new file mode 100644 index 00000000..80f43088 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleLightning.java @@ -0,0 +1,167 @@ +package electroblob.wizardry.client.particle; + +import java.util.Random; + +import org.lwjgl.opengl.GL11; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.world.World; + +public class ParticleLightning extends ParticleTargeted { + + /** Half the width of the outermost layer. */ + private static final float THICKNESS = 0.04f; + /** Maximum length of a segment. */ + private static final double MAX_SEGMENT_LENGTH = 0.6; + /** Minimum length of a segment. */ + private static final double MIN_SEGMENT_LENGTH = 0.2; + /** Maximum deviation (in x or y, as drawn before transformations) from the centreline. */ + private static final double VERTEX_JITTER = 0.15; + /** Maximum number of segments a fork can have before ending. */ + private static final int MAX_FORK_SEGMENTS = 3; + /** Probability (as a fraction) that a vertex will have a fork. */ + private static final float FORK_CHANCE = 0.3f; + /** Number of ticks to wait before the arc changes shape again. */ + private static final int UPDATE_PERIOD = 1; + + /** A random long value used by the renderer as a seed to generate its vertices from, ensuring they remain the same + * across multiple frames. Not synced. */ + public final long seed; + + public ParticleLightning(World world, double x, double y, double z){ + super(world, x, y, z); // Does not have a texture! + seed = this.rand.nextLong(); + this.setRBGColorF(0.2f, 0.6f, 1); // Default blue colour + this.setMaxAge(3); + this.particleScale = 1; + } + + @Override + public int getFXLayer(){ + return 3; + } + + @Override + protected void draw(Tessellator tessellator, double length, float partialTicks){ + + GlStateManager.disableLighting(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); + + // The direction of the arc drawn by the tessellator is always along the z axis and is rotated to the + // correct orientation, that way there isn't a ton of trigonometry and the code is way neater. + + boolean freeEnd = this.target == null; + + int numberOfSegments = (int)Math.round(length/MAX_SEGMENT_LENGTH); // Number of segments + + for(int layer=0; layer<3; layer++){ + + double px=0, py=0, pz=0; + // Creates a random from the arc's seed field + the number of ticks it has existed/the update period. + // By using a seed, we can ensure the vertex positions and forks are identical a) for each layer, even + // though they are rendered sequentially, and b) across many frames (and ticks, if updateTime > 1). + Random random = new Random(this.seed + this.particleAge/UPDATE_PERIOD); + + // numberOfSegments-1 because the last segment is handled separately. + for(int i=0; i= this.particleMaxAge){ - this.setExpired(); - } - - // This is in radians per tick... - double omega = Math.signum(speed) * ((Math.PI * 2) / 20 - speed / (20 * radius)); - - // v = r times omega; therefore the normalised velocity vector needs to be r times the angle increment / 2 pi. - this.angle += omega; - - this.motionY -= 0.04D * (double)this.particleGravity; - this.motionZ = radius * omega * Math.cos(angle); - this.motionX = radius * omega * Math.sin(angle); - this.move(motionX, motionY, motionZ); - - if(this.particleAge > this.particleMaxAge / 2){ - this.setAlphaF( - 1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); - } - - } -} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleScorch.java b/src/main/java/electroblob/wizardry/client/particle/ParticleScorch.java new file mode 100644 index 00000000..3523cfa6 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleScorch.java @@ -0,0 +1,70 @@ +package electroblob.wizardry.client.particle; + +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleScorch extends ParticleWizardry { + + private static final ResourceLocation[] TEXTURES = generateTextures("scorch", 8); + + public ParticleScorch(World world, double x, double y, double z){ + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + + this.particleGravity = 0; + this.setMaxAge(100 + rand.nextInt(40)); + this.particleScale *= 2; + // Defaults to black (which looks like a 'normal' scorch mark) + this.setRBGColorF(0, 0, 0); + this.shaded = false; + } + + @Override + public void setRBGColorF(float r, float g, float b){ + super.setRBGColorF(r, g, b); + this.setFadeColour(0, 0, 0); // Scorch particles fade to black by default + } + + @Override + public void onUpdate(){ + + super.onUpdate(); + + // Colour fading (scorch particles do this slightly differently) + float ageFraction = Math.min((float)this.particleAge / ((float)this.particleMaxAge * 0.5f), 1); + // No longer uses setRBGColorF because that method now also sets the initial values + this.particleRed = this.initialRed + (this.fadeRed - this.initialRed) * ageFraction; + this.particleGreen = this.initialGreen + (this.fadeGreen - this.initialGreen) * ageFraction; + this.particleBlue = this.initialBlue + (this.fadeBlue - this.initialBlue) * ageFraction; + + // Fading + if(this.particleAge > this.particleMaxAge/2){ + this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge/2)) / (float)this.particleMaxAge); + } + + EnumFacing facing = EnumFacing.fromAngle(yaw); + if(pitch == 90) facing = EnumFacing.UP; + if(pitch == -90) facing = EnumFacing.DOWN; + + // Disappears if there is no block behind it (this is the same check used to spawn it) + if(!world.getBlockState(new BlockPos(posX, posY, posZ).offset(facing.getOpposite())).getMaterial().isSolid()){ + this.setExpired(); + } + } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } + } +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java index a18ff4d9..e5de49f9 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSnow.java @@ -1,39 +1,36 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleSnow extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleSnow extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/snow_particles.png"); + private static final ResourceLocation[] TEXTURES = generateTextures("snow", 4); public ParticleSnow(World world, double x, double y, double z){ - super(world, x, y, z); - this.setParticleTextureIndex(rand.nextInt(8)); + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.setVelocity(0, -0.02, 0); this.particleScale *= 0.6f; this.particleGravity = 0; this.canCollide = true; - this.setLifetime(40 + rand.nextInt(10)); + this.setMaxAge(40 + rand.nextInt(10)); + // Produces a variety of light blues and whites + this.setRBGColorF(0.9f + 0.1f * world.rand.nextFloat(), 0.95f + 0.05f * world.rand.nextFloat(), 1); } - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java index a94103f1..5d879ad0 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSpark.java @@ -1,66 +1,55 @@ package electroblob.wizardry.client.particle; -import org.lwjgl.opengl.GL11; - -import electroblob.wizardry.Wizardry; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleSpark extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleSpark extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/lightning_particles.png"); + // 8 different animation strips, 4 in each strip + private static final ResourceLocation[][] TEXTURES = generateTextures("lightning", 8, 4); public ParticleSpark(World world, double x, double y, double z){ - super(world, x, y, z); - // Multiplied by 4 because the index works slightly differently for spark particles. - this.setParticleTextureIndex(rand.nextInt(8) * 4); + + super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]); + this.particleScale *= 1.4f; + this.setRBGColorF(1, 1, 1); this.shaded = false; this.canCollide = false; - this.setLifetime(3); // Lifetime defaults to 3 (and is very unlikely to be changed) + this.setMaxAge(3); // Lifetime defaults to 3 (and is very unlikely to be changed) } + + // May no longer be necessary, ParticleManager seems to enable blending now - @Override - public void onUpdate(){ - super.onUpdate(); - // Well this is handy! Looks like vanilla uses the texture index like this too. - this.nextTextureIndexX(); - } - - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 8; - } - - @Override - public void applyGLStateChanges(){ - GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - // TESTME: Are these two actually necessary? - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); - } - - @Override - public void undoGLStateChanges(){ - GlStateManager.disableBlend(); - GlStateManager.enableLighting(); +// @Override +// public void applyGLStateChanges(){ +// GlStateManager.enableBlend(); +// GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); +// // TESTME: Are these two actually necessary? +// GlStateManager.disableLighting(); +// OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); +// } +// +// @Override +// public void undoGLStateChanges(){ +// GlStateManager.disableBlend(); +// GlStateManager.enableLighting(); +// } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation[] array : TEXTURES){ + for(ResourceLocation texture : array){ + event.getMap().registerSprite(texture); + } + } } } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java index f63bfcfb..4aa64a35 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleSparkle.java @@ -1,24 +1,23 @@ package electroblob.wizardry.client.particle; -import electroblob.wizardry.Wizardry; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) -public class ParticleSparkle extends ParticleCustomTexture { +@Mod.EventBusSubscriber(Side.CLIENT) +public class ParticleSparkle extends ParticleWizardry { - private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, - "textures/particle/sparkle_particles.png"); - - // Implementation of colour fading (perhaps these belong in ParticleWizardry?) - private float initialRed; - private float initialGreen; - private float initialBlue; + private static final ResourceLocation[] TEXTURES = generateTextures("sparkle", 11); public ParticleSparkle(World world, double x, double y, double z){ - super(world, x, y, z); + + super(world, x, y, z, TEXTURES); // This time the textures are all one long animation + this.setRBGColorF(1, 1, 1); this.particleMaxAge = 48 + this.rand.nextInt(12); this.particleScale *= 0.75f; @@ -27,30 +26,6 @@ public class ParticleSparkle extends ParticleCustomTexture { this.shaded = false; } - // Overridden to set the initial colour values - @Override - public void setRBGColorF(float r, float g, float b){ - super.setRBGColorF(r, g, b); - initialRed = r; - initialGreen = g; - initialBlue = b; - } - - @Override - public ResourceLocation getTexture(){ - return TEXTURE; - } - - @Override - protected int getXFrames(){ - return 4; - } - - @Override - protected int getYFrames(){ - return 4; - } - @Override public void onUpdate(){ @@ -58,24 +33,14 @@ public class ParticleSparkle extends ParticleCustomTexture { // Fading if(this.particleAge > this.particleMaxAge / 2){ - this.setAlphaF( - 1.0F - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge); + } + } + + @SubscribeEvent + public static void onTextureStitchEvent(TextureStitchEvent.Pre event){ + for(ResourceLocation texture : TEXTURES){ + event.getMap().registerSprite(texture); } - - // Colour fading - float ageFraction = (float)this.particleAge / (float)this.particleMaxAge; - // No longer uses setRBGColorF because that method now also sets the initial values - this.particleRed = this.initialRed + (this.fadeRed - this.initialRed)*ageFraction; - this.particleGreen = this.initialGreen + (this.fadeGreen - this.initialGreen)*ageFraction; - this.particleBlue = this.initialBlue + (this.fadeBlue - this.initialBlue)*ageFraction; - - this.setParticleTextureIndex((this.particleAge * 11)/this.particleMaxAge); } - - /* As a side note, I see a lot of magic mods with fancy-looking particle effects that really seem to 'glow'. It's - * actually not that hard - you simply create a reasonably high-res texture with translucency and then set the - * OpenGL blend function to something like SRC_ALPHA, SRC_ALPHA or ONE, ONE. The thing is... they're not very - * Minecraft-y. I still maintain that part of wizardry's appeal is that it stays true to the game's pixelated charm, - * rather than trying to make it something it's not. Still, the newer textures are much better than the defaults I - * used to use. */ } diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java b/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java new file mode 100644 index 00000000..80ce3e59 --- /dev/null +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleTargeted.java @@ -0,0 +1,105 @@ +package electroblob.wizardry.client.particle; + +import javax.annotation.Nullable; + +import org.lwjgl.opengl.GL11; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +/** Superclass for particles with a second target entity or target position. */ +public abstract class ParticleTargeted extends ParticleWizardry { + + protected double targetX; + protected double targetY; + protected double targetZ; + + /** The target this particle is linked to. The particle will stretch to touch this entity. */ + @Nullable + protected Entity target = null; + + public ParticleTargeted(World world, double x, double y, double z, ResourceLocation... textures){ + super(world, x, y, z, textures); + } + + @Override + public void setTargetPosition(double x, double y, double z){ + this.targetX = x; + this.targetY = y; + this.targetZ = z; + } + + @Override + public void setTargetEntity(Entity target){ + this.target = target; + } + + @Override + public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, float rotationYZ, + float rotationXY, float rotationXZ){ + + if(this.target != null){ + this.targetX = this.target.posX; + this.targetY = this.target.getEntityBoundingBox().minY + target.height/2; + this.targetZ = this.target.posZ; + } + + if(Double.isNaN(targetX) || Double.isNaN(targetY) || Double.isNaN(targetZ)){ + Wizardry.logger.warn("Attempted to render a targeted particle, but neither its target entity nor target" + + "position was set!"); + return; + } + + // I'm pretty sure these were always static. + interpPosX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * (double)partialTicks; + interpPosY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * (double)partialTicks; + interpPosZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * (double)partialTicks; + + float x = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX); + float y = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); + float z = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); + + GlStateManager.pushMatrix(); + GlStateManager.translate(x, y, z); + + double dx = this.targetX - this.posX; + double dy = this.targetY - this.posY; + double dz = this.targetZ - this.posZ; + + // The distance from origin to endpoint + double length = Math.sqrt(dx*dx+dy*dy+dz*dz); + + // Math.atan2 computes within -180 to +180, rather than -90 to +90. + float yaw = (float)(180d/Math.PI * Math.atan2(dx, dz)); + float pitch = (float)(180f/(float)Math.PI * Math.atan(-dy/Math.sqrt(dz*dz+dx*dx))); + + GL11.glRotatef(yaw, 0, 1, 0); + GL11.glRotatef(pitch, 1, 0, 0); + + Tessellator tessellator = Tessellator.getInstance(); + + this.draw(tessellator, length, partialTicks); + + GlStateManager.popMatrix(); + } + + /** Called from {@link ParticleTargeted#renderParticle(BufferBuilder, Entity, float, float, float, float, float, float)}, + * once the appropriate calculations and transformations have been applied, to actually render the particle. Subclasses + * override this instead of overriding {@code renderParticle} directly, and inside render the particle along + * the z-axis, starting at (0, 0, 0) - it will be translated and rotated automatically. + *

+ * N.B. Other than transformations, no GL state changes are applied; these should be done within this method. + * + * @param tessellator A reference to the tessellator, for convenience. + * @param length The distance from the origin to the endpoint for the particle being rendered; the particle should + * therefore be rendered between (0, 0, 0) and (0, 0, length) within this method. + * @param partialTicks The partial tick time. + */ + protected abstract void draw(Tessellator tessellator, double length, float partialTicks); + +} diff --git a/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java index 607c4da5..62f96e7f 100644 --- a/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java +++ b/src/main/java/electroblob/wizardry/client/particle/ParticleWizardry.java @@ -1,7 +1,20 @@ package electroblob.wizardry.client.particle; +import java.util.Arrays; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +import electroblob.wizardry.Wizardry; +import net.minecraft.client.Minecraft; import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; import net.minecraft.world.World; +import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -9,7 +22,7 @@ import net.minecraftforge.fml.relauncher.SideOnly; * Abstract superclass for all of wizardry's particles. This replaces {@code ParticleCustomTexture} (the functionality of * which is no longer necessary since wizardry now uses {@code TextureAtlasSprite}s to do the rendering), and fits into * {@code ParticleBuilder} by exposing all the necessary variables through getters, allowing them to be set on the fly - * rather than needing to be passed into the constructor. + * rather than needing to be passed into the constructor. *

* The new system is as follows: *

@@ -17,28 +30,94 @@ import net.minecraftforge.fml.relauncher.SideOnly; * - Each particle class defines any relevant default values in its constructor, including velocity.
* - The particle builder then overwrites any other values that were set during building. *

- * This beauty of this system is that there are never any redundant parameters when spawning particles. For example, + * This beauty of this system is that there are never any redundant parameters when spawning particles, since you can set + * as many or as few parameters as necessary - and in addition, common defaults don't need setting at all. For example, * snow particles nearly always fall at the same speed, which can now be defined in the particle class and no longer * needs to be defined when spawning the particle - but importantly, it can still be overridden if desired. * * @author Electroblob - * @since Wizardry 4.2.0 + * @since Wizardry 4.2.0 * @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder */ @SideOnly(Side.CLIENT) public abstract class ParticleWizardry extends Particle { + /** Implementation of animated particles using the TextureAtlasSprite system. Why vanilla doesn't support this I + * don't know, considering it too has animated particles. */ + protected final TextureAtlasSprite[] sprites; + /** True if the particle is shaded, false if the particle always renders at full brightness. Defaults to false. */ protected boolean shaded = false; - - protected float fadeRed = 1; - protected float fadeGreen = 1; - protected float fadeBlue = 0; - public ParticleWizardry(World world, double x, double y, double z){ + protected float initialRed; + protected float initialGreen; + protected float initialBlue; + + protected float fadeRed = 0; + protected float fadeGreen = 0; + protected float fadeBlue = 0; + + protected float angle; + protected double radius = 0; + protected double speed = 0; + + /** The entity this particle is linked to. The particle will move with this entity. */ + @Nullable + protected Entity entity = null; + /** Coordinates of this particle relative to the linked entity. If the linked entity is null, these are not used. */ + protected double relativeX, relativeY, relativeZ; + /** Velocity of this particle relative to the linked entity. The relative x and z velocities are also used when + * the particle has spin to move the centre of rotation. If the linked entity is null and the particle is not + * spinning, these are not used and will be {@code NaN}. */ + protected double relativeMotionX = Double.NaN, relativeMotionY = Double.NaN, relativeMotionZ = Double.NaN; + // Note that roll (equivalent to rotating the texture) is effectively handled by particleAngle - although that is + // actually the rotation speed and not the angle itself. + /** The yaw angle this particle is facing, or {@code NaN} if this particle always faces the viewer (default behaviour). */ + protected float yaw = Float.NaN; + /** The pitch angle this particle is facing, or {@code NaN} if this particle always faces the viewer (default behaviour). */ + protected float pitch = Float.NaN; + + /** + * Creates a new particle in the given world at the given position. All other parameters are set via the various + * setter methods ({@link electroblob.wizardry.util.ParticleBuilder ParticleBuilder} deals with all of that anyway). + * @param world The world in which to create the particle. + * @param x The x-coordinate at which to create the particle. + * @param y The y-coordinate at which to create the particle. + * @param z The z-coordinate at which to create the particle. + * @param textures One or more {@code ResourceLocation}s representing the texture(s) used by this particle. These + * must be registered as {@link TextureAtlasSprite}s using {@link TextureStitchEvent} or the textures will be + * missing. If more than one {@code ResourceLocation} is specified, the particle will be animated with each texture + * shown in order for an equal proportion of the particle's lifetime. If this argument is omitted (or a zero-length + * array is given), the particle will use the vanilla system instead (based on the X/Y texture indices). + */ + public ParticleWizardry(World world, double x, double y, double z, ResourceLocation... textures){ + super(world, x, y, z); + + // Sets the relative coordinates in case they are needed + this.relativeX = x; + this.relativeY = y; + this.relativeZ = z; + + // Deals with the textures + if(textures.length > 0){ + + sprites = Arrays.stream(textures).map(t -> Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( + t.toString())).collect(Collectors.toList()).toArray(new TextureAtlasSprite[0]); + + this.setParticleTexture(sprites[0]); + + }else{ + + sprites = new TextureAtlasSprite[0]; + } } + // ============================================== Parameter Setters ============================================== + + // Setters for parameters that affect all particles - these are implemented in this class (although they may be + // reimplemented in subclasses) + /** Sets whether the particle should render at full brightness or not. True if the particle is shaded, false if * the particle always renders at full brightness. Defaults to false.*/ public void setShaded(boolean shaded){ @@ -50,9 +129,9 @@ public abstract class ParticleWizardry extends Particle { this.particleGravity = gravity ? 1 : 0; } - /** Sets this particle's lifetime in ticks.*/ - public void setLifetime(int lifetime){ - this.particleMaxAge = lifetime; + /** Sets this particle's collisions. True to enable block collisions, false to disable. Defaults to false.*/ + public void setCollisions(boolean canCollide){ + this.canCollide = canCollide; } /** @@ -67,25 +146,252 @@ public abstract class ParticleWizardry extends Particle { this.motionZ = vz; } + /** + * Sets the spin parameters of the particle. + * @param radius The spin radius + * @param speed The spin speed in rotations per tick + */ + public void setSpin(double radius, double speed){ + this.radius = radius; + this.speed = speed * 2 * Math.PI; // Converts rotations per tick into radians per tick for the trig functions + this.angle = this.rand.nextFloat() * (float)Math.PI * 2; // Random start angle TODO: Perhaps this should be specified? + // Need to set the start position or the circle won't be centred on the correct position + this.relativeX = radius * -MathHelper.cos(angle); + this.relativeZ = radius * MathHelper.sin(angle); + this.setPosition(posX + relativeX, posY, posZ + relativeZ); + this.prevPosX = posX; + this.prevPosZ = posZ; + // Set these to the correct values + this.relativeMotionX = motionX; + this.relativeMotionY = motionY; + this.relativeMotionZ = motionZ; + } + + /** + * Links this particle to the given entity. This will cause its position and velocity to be relative to the entity. + * @param entity The entity to link to. + */ + public void setEntity(Entity entity){ + this.entity = entity; + // Set these to the correct values + if(entity != null){ + this.setPosition(this.entity.posX + relativeX, this.entity.getEntityBoundingBox().minY + + relativeY, this.entity.posZ + relativeZ); + this.prevPosX = this.posX; + this.prevPosY = this.posY; + this.prevPosZ = this.posZ; + this.relativeMotionX = motionX; + this.relativeMotionY = motionY; + this.relativeMotionZ = motionZ; + } + } + + // Overridden to set the initial colour values + /** + * Sets the base colour of the particle. Note that this also sets the fade colour so that particles without a + * fade colour do not change colour at all; as such fade colour must be set after calling this method. + * @param r The red colour component + * @param g The green colour component + * @param b The blue colour component + */ + @Override + public void setRBGColorF(float r, float g, float b){ + super.setRBGColorF(r, g, b); + initialRed = r; + initialGreen = g; + initialBlue = b; + // If fade colour is not specified, it defaults to the main colour - this method is always called first + setFadeColour(r, g, b); + } + /** * Sets the fade colour of the particle. * @param r The red colour component * @param g The green colour component - * @param g The blue colour component + * @param b The blue colour component */ public void setFadeColour(float r, float g, float b){ this.fadeRed = r; this.fadeGreen = g; this.fadeBlue = b; } + + /** + * Sets the direction this particle faces. This will cause the particle to render facing the given direction. + * @param yaw The yaw angle of this particle in degrees, where 0 is [TODO south?]. + * @param pitch The pitch angle of this particle in degrees, where 0 is horizontal. + */ + public void setFacing(float yaw, float pitch){ + this.yaw = yaw; + this.pitch = pitch; + } + + // Setters for parameters that only affect some particles - these are unimplemented in this class because they + // doesn't make sense for most particles + + /** + * Sets the target position for this particle. This will cause it to stretch to touch the given position, + * if supported. + * @param x The x-coordinate of the target position. + * @param y The y-coordinate of the target position. + * @param z The z-coordinate of the target position. + */ + public void setTargetPosition(double x, double y, double z){ + // Does nothing for normal particles since normal particles always render at a single point + } + + /** + * Links this particle to the given target. This will cause it to stretch to touch the target, if supported. + * @param target The target to link to. + */ + public void setTargetEntity(Entity target){ + // Does nothing for normal particles since normal particles always render at a single point + } + + // ============================================== Method Overrides ============================================== + + @Override + public int getFXLayer(){ + return sprites.length == 0 ? super.getFXLayer() : 1; // This has to be 1 for the TextureAtlasSprites to work + } @Override public int getBrightnessForRender(float partialTick){ return shaded ? super.getBrightnessForRender(partialTick) : 15728880; } + + /** + * Renders the particle. The mapping names given to the parameters in this method are very misleading; see below for + * details of what they actually do. (They're also in a strange order...) + * @param buffer The {@code BufferBuilder} object. + * @param viewer The entity whose viewpoint the particle is being rendered from; this should always be the + * client-side player. + * @param partialTicks The partial tick time. + * @param lookZ Equal to the cosine of {@code viewer.rotationYaw}. Will be -1 when facing north (negative Z), 0 when + * east/west, and +1 when facing south (positive Z). Independent of pitch. + * @param lookY Equal to the cosine of {@code viewer.rotationPitch}. Will be 1 when facing directly up or down, and 0 + * when facing directly horizontally. + * @param lookX Equal to the sine of {@code viewer.rotationYaw}. Will be -1 when facing east (positive X), 0 when + * facing north/south, and +1 when facing west (negative X). Independent of pitch. + * @param lookXY Equal to {@code lookX} times the sine of {@code viewer.rotationPitch}. Will be 0 when facing directly horizontal. + * When facing directly up, will be equal to {@code -lookX}. When facing directly down, will be equal to {@code lookX}. + * @param lookYZ Equal to {@code -lookZ} times the sine of {@code viewer.rotationPitch}. Will be 0 when facing directly horizontal. + * When facing directly up, will be equal to {@code -lookZ}. When facing directly down, will be equal to {@code lookZ}. + */ + @Override + public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float lookZ, float lookY, + float lookX, float lookXY, float lookYZ){ + + if(Float.isNaN(this.yaw) || Float.isNaN(this.pitch)){ + + // Normal behaviour (rotates to face the viewer) + super.renderParticle(buffer, viewer, partialTicks, lookZ, lookY, lookX, lookXY, lookYZ); + + }else{ + + // Specific rotation + + // Copied from ActiveRenderInfo; converts yaw and pitch into the weird parameters used by renderParticle. + // The 1st/3rd person distinction has been removed since this has nothing to do with the view angle. + + float degToRadFactor = 0.017453292f; // Conversion from degrees to radians + + float rotationX = MathHelper.cos(yaw * degToRadFactor); + float rotationZ = MathHelper.sin(yaw * degToRadFactor); + float rotationY = MathHelper.cos(pitch * degToRadFactor); + float rotationYZ = -rotationZ * MathHelper.sin(pitch * degToRadFactor); + float rotationXY = rotationX * MathHelper.sin(pitch * degToRadFactor); + + super.renderParticle(buffer, viewer, partialTicks, rotationX, rotationY, rotationZ, rotationYZ, rotationXY); + } + } + + @Override + public void onUpdate(){ - /** Simple particle factory interface which takes a world and a position and returns a particle. Used (via lambda - * expressions) in the client proxy to link particle enum types to actual particle classes. */ + super.onUpdate(); + + // If any of these values is NaN, the particle has neither an entity nor a spin + if(!Double.isNaN(relativeMotionX) && !Double.isNaN(relativeMotionY) && !Double.isNaN(relativeMotionZ)){ + + // This allows velocity changes from entity linking and spin to stack + double vx = relativeMotionX; + double vy = relativeMotionY; + double vz = relativeMotionZ; + + // Entity linking + if(this.entity != null){ + + if(this.entity.isDead) this.setExpired(); + + this.setPosition(this.entity.posX + relativeX, this.entity.getEntityBoundingBox().minY + relativeY, + this.entity.posZ + relativeZ); + // Velocity is set so that the renderer will interpolate correctly between ticks + vx += this.entity.motionX; + vy += this.entity.motionY; + vz += this.entity.motionZ; + } + + // Spin + if(radius > 0){ + angle += speed; + vx += radius * speed * MathHelper.sin(angle); + vz += radius * speed * MathHelper.cos(angle); + } + + this.relativeX += vx; + this.relativeY += vy; + this.relativeZ += vz; + } + + // Colour fading + float ageFraction = (float)this.particleAge / (float)this.particleMaxAge; + // No longer uses setRBGColorF because that method now also sets the initial values + this.particleRed = this.initialRed + (this.fadeRed - this.initialRed) * ageFraction; + this.particleGreen = this.initialGreen + (this.fadeGreen - this.initialGreen) * ageFraction; + this.particleBlue = this.initialBlue + (this.fadeBlue - this.initialBlue) * ageFraction; + + // Animation + if(sprites.length > 1){ + // Math.min included for safety so the index cannot possibly exceed the length - 1 an cause an AIOOBE + // (which would probably otherwise happen if particleAge == particleMaxAge) + this.setParticleTexture(sprites[Math.min((int)(ageFraction * sprites.length), sprites.length - 1)]); + } + } + + // =============================================== Helper Methods =============================================== + + /** Static helper method that generates an array of n ResourceLocations using the particle file naming convention, + * which is the given stem plus an underscore plus the integer index. */ + public static ResourceLocation[] generateTextures(String stem, int n){ + + ResourceLocation[] textures = new ResourceLocation[n]; + + for(int i=0; i { - - public RenderArc(RenderManager renderManager){ - super(renderManager); - } - - @Override - public void doRender(EntityArc arc, double x, double y, double z, float viewPitch, float viewYaw) { - - GlStateManager.pushMatrix(); - GlStateManager.translate(x, y, z); - GlStateManager.disableLighting(); - GlStateManager.enableBlend(); - GlStateManager.disableTexture2D(); - GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f); - - Tessellator tessellator = Tessellator.getInstance(); - - /* Note: A lot of the maths here works on similar triangles and the ratios between them, avoiding too much - * pythagoras and eliminating the need for any trig. Ratios are used for the positioning of the arc endpoints. - * Ratios are usually used swapping x and z because the triangles are rotated through 90 degrees. */ - - double dx = -x; - double dy = -y; - double dz = -z; - - if(arc.x1 != 0){ - - dx = arc.x1 - arc.posX; - dy = arc.y1 - arc.posY; - dz = arc.z1 - arc.posZ; - - // The distance from origin to endpoint - double arcLength = Math.sqrt(dx*dx+dy*dy+dz*dz); - - GL11.glTranslated(dx, dy, dz); - - // Math.atan2 computes within -180 to +180, rather than -90 to +90. - float yaw = (float)(180d/Math.PI * Math.atan2(-dx, -dz)); - float pitch = (float)(180f/(float)Math.PI * Math.atan(dy/Math.sqrt(dz*dz+dx*dx))); - - GL11.glRotatef(yaw, 0, 1, 0); - GL11.glRotatef(pitch, 1, 0, 0); - - // The direction of the arc drawn by the tessellator is always along the z axis and is rotated to the - // correct orientation, that way there isn't a ton of trigonometry and the code is way neater. - - boolean freeEnd = arc.freeEnd; - - // == To be extracted as constants later == - float thickness = 0.04f; // Half the width of the outermost layer - double maxSegmentLength = 0.6; // Max length of a segment, obviously - double minSegmentLength = 0.2; // Min length of a segment - double vertexDither = 0.15; // Max deviation in x or y axis from the centreline - int maxForkSegments = 3; // Max number of segments a fork can have - float forkChance = 0.3f; // Chance (as a fraction) that a vertex will have a fork - int updateTime = 1; // Number of ticks to wait before the arc changes shape again - - int numberOfSegments = (int)Math.round(arcLength/maxSegmentLength); // Number of segments - - for(int layer=0; layer<3; layer++){ - - double px=0, py=0, pz=0; - // Creates a random from the arc's seed field + the number of ticks it has existed/the update period. - // By using a seed, we can ensure the vertex positions and forks are identical a) for each layer, even - // though they are rendered sequentially, and b) across many frames (and ticks, if updateTime > 1). - Random random = new Random(arc.seed + arc.ticksExisted/updateTime); - - // numberOfSegments-1 because the last segment is handled separately. - for(int i=0; i { - - private final ResourceLocation[] textures = new ResourceLocation[8]; - private float scale = 1.0f; - - public RenderLightningPulse(RenderManager renderManager, float scale){ - super(renderManager); - for(int i = 0; i < textures.length; i++){ - textures[i] = new ResourceLocation(Wizardry.MODID, "textures/entity/lightning_pulse_" + i + ".png"); - } - this.scale = scale; - } - - @Override - public void doRender(EntityLightningPulse entity, double par2, double par4, double par6, float par8, float par9){ - - GlStateManager.pushMatrix(); - GlStateManager.enableBlend(); - GlStateManager.disableLighting(); - OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - - float yOffset = 0; - - GlStateManager.translate((float)par2, (float)par4 + yOffset, (float)par6); - - this.bindTexture(textures[entity.ticksExisted]); - float f6 = 1.0F; - float f7 = 0.5F; - float f8 = 0.5F; - - GlStateManager.rotate(-90, 1, 0, 0); - - GlStateManager.scale(scale, scale, scale); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); - buffer.pos((double)(0.0F - f7), (double)(0.0F - f8), 0.01).tex(0, 1).endVertex(); - buffer.pos((double)(f6 - f7), (double)(0.0F - f8), 0.01).tex(1, 1).endVertex(); - buffer.pos((double)(f6 - f7), (double)(1.0F - f8), 0.01).tex(1, 0).endVertex(); - buffer.pos((double)(0.0F - f7), (double)(1.0F - f8), 0.01).tex(0, 0).endVertex(); - - tessellator.draw(); - - GlStateManager.disableBlend(); - GlStateManager.enableLighting(); - GlStateManager.disableRescaleNormal(); - GlStateManager.popMatrix(); - } - - @Override - protected ResourceLocation getEntityTexture(EntityLightningPulse entity){ - return null; - } - -} diff --git a/src/main/java/electroblob/wizardry/entity/EntityArc.java b/src/main/java/electroblob/wizardry/entity/EntityArc.java deleted file mode 100644 index f3c729ae..00000000 --- a/src/main/java/electroblob/wizardry/entity/EntityArc.java +++ /dev/null @@ -1,78 +0,0 @@ -package electroblob.wizardry.entity; - -import io.netty.buffer.ByteBuf; -import net.minecraft.entity.Entity; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.world.World; -import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; - -public class EntityArc extends Entity implements IEntityAdditionalSpawnData { - - public double x1, y1, z1, x2, y2, z2; - /** The number of ticks the arc lasts for before disappearing. */ - public int lifetime = 3; - /** False if the arc is locked to an entity, true otherwise. False by default. */ - public boolean freeEnd = false; - /** A random long value used by the renderer as a seed to generate its vertices from, ensuring they remain the same - * across multiple frames. Not synced. */ - public final long seed; - - public EntityArc(World par1World){ - super(par1World); - seed = this.rand.nextLong(); - this.ignoreFrustumCheck = true; - } - - public void setEndpointCoords(double x1, double y1, double z1, double x2, double y2, double z2){ - this.x1 = x1; - this.y1 = y1; - this.z1 = z1; - this.x2 = x2; - this.y2 = y2; - this.z2 = z2; - this.setPosition(x2, y2, z2); - } - - @Override - public void onUpdate(){ - if(this.ticksExisted >= lifetime){ - this.setDead(); - } - } - - protected void entityInit(){ - } - - @Override - protected void readEntityFromNBT(NBTTagCompound nbttagcompound){ - - } - - @Override - protected void writeEntityToNBT(NBTTagCompound nbttagcompound){ - // Nothing needed here; arc is merely a graphic effect that only exists for a few ticks; as such there is no - // need to save it. - } - - @Override - public boolean isInRangeToRenderDist(double distance){ - return true; - } - - @Override - public void writeSpawnData(ByteBuf data){ - data.writeDouble(this.x1); - data.writeDouble(this.y1); - data.writeDouble(this.z1); - data.writeBoolean(freeEnd); - } - - @Override - public void readSpawnData(ByteBuf data){ - this.x1 = data.readDouble(); - this.y1 = data.readDouble(); - this.z1 = data.readDouble(); - this.freeEnd = data.readBoolean(); - } - -} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java index c45abe77..4d863e0f 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityBlizzard.java @@ -53,24 +53,13 @@ public class EntityBlizzard extends EntityMagicConstruct { if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 20, 0)); } + }else{ - for(int i=1; i<6; i++){ - - float brightness = 0.5f + (rand.nextFloat() / 2); - - ParticleBuilder.create(Type.BLIZZARD) - .pos(this.posX, this.posY + rand.nextDouble() * 3, this.posZ) - .lifetime(100) - .colour(brightness, brightness + 0.1f, 1.0f) - .radius(rand.nextDouble() * 2.5d + 0.5d) - .spawn(world); - - ParticleBuilder.create(Type.BLIZZARD) - .pos(this.posX, this.posY + rand.nextDouble() * 3, this.posZ) - .lifetime(100) - .colour(1, 1, 1) - .radius(rand.nextDouble() * 2.5d + 0.5d) - .spawn(world); + + for(int i=1; i<12; i++){ + double speed = (rand.nextBoolean() ? 1 : -1) * 0.1 + 0.05 * rand.nextDouble(); + ParticleBuilder.create(Type.SNOW).pos(this.posX, this.posY + rand.nextDouble() * 3, this.posZ).vel(0, 0, 0) + .time(100).scale(2).spin(rand.nextDouble() * 2.5 + 0.5, speed).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java index 6c40f523..7507cbca 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityDecay.java @@ -53,7 +53,7 @@ public class EntityDecay extends EntityMagicConstruct { ParticleBuilder.create(Type.DARK_MAGIC) .pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) - .colour(brightness, 0, brightness + 0.1f) + .clr(brightness, 0, brightness + 0.1f) .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java index 7ad68328..2a1ab31d 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityForcefield.java @@ -66,8 +66,8 @@ public class EntityForcefield extends EntityMagicConstruct { ParticleBuilder.create(Type.DUST) .pos(this.posX + radius * Math.cos(yaw) * Math.cos(pitch), this.posY + 3 + radius * Math.sin(pitch), this.posZ + radius * Math.sin(yaw) * Math.cos(pitch)) - .lifetime(48 + this.rand.nextInt(12)) - .colour(brightness, brightness, 1.0f).spawn(world); + .time(48 + this.rand.nextInt(12)) + .clr(brightness, brightness, 1.0f).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java index 6f174d91..80bec470 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHammer.java @@ -3,7 +3,6 @@ package electroblob.wizardry.entity.construct; import java.util.List; import electroblob.wizardry.Wizardry; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; @@ -98,24 +97,12 @@ public class EntityHammer extends EntityMagicConstruct { if(this.isValidTarget(target)){ - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(this.posX, this.posY + this.height - 0.1, this.posZ, target.posX, - target.posY + target.height / 2, target.posZ); - world.spawnEntity(arc); - }else{ - // TODO: Move all the arc particle (and sound?) stuff into a method in WizardryUtilities - for(int j=0; j<8; j++){ - ParticleBuilder.create(Type.SPARK) - .pos(target.posX + world.rand.nextFloat() - 0.5, - target.getEntityBoundingBox().minY + target.height / 2 + world.rand.nextFloat() * 2 - 1, - target.posZ + world.rand.nextFloat() - 0.5) - .spawn(world); - - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, target.posX + rand.nextFloat(), - target.getEntityBoundingBox().minY + target.height / 2 + rand.nextFloat(), - target.posZ + rand.nextFloat(), 0, 0, 0); - } + if(world.isRemote){ + + ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world); + + ParticleBuilder.spawnShockParticles(world, target.posX, + target.getEntityBoundingBox().minY + target.height, target.posZ); } target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java index 32e893f7..14406109 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityHealAura.java @@ -69,8 +69,8 @@ public class EntityHealAura extends EntityMagicConstruct { ParticleBuilder.create(Type.SPARKLE) .pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) .vel(0, 0.05, 0) - .lifetime(48 + this.rand.nextInt(12)) - .colour(1.0f, 1.0f, brightness) + .time(48 + this.rand.nextInt(12)) + .clr(1.0f, 1.0f, brightness) .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java deleted file mode 100644 index b2d46ab5..00000000 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningPulse.java +++ /dev/null @@ -1,18 +0,0 @@ -package electroblob.wizardry.entity.construct; - -import net.minecraft.world.World; - -@Deprecated // This needs changing into a particle -public class EntityLightningPulse extends EntityMagicConstruct { - - public EntityLightningPulse(World world){ - super(world); - this.setSize(6, 0.2f); - } - - @Override - public boolean canRenderOnFire(){ - return false; - } - -} diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java index 62dcea76..589cea82 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityLightningSigil.java @@ -2,7 +2,6 @@ package electroblob.wizardry.entity.construct; import java.util.List; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; @@ -11,7 +10,6 @@ import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.DamageSource; -import net.minecraft.util.EnumParticleTypes; import net.minecraft.world.World; public class EntityLightningSigil extends EntityMagicConstruct { @@ -65,25 +63,14 @@ public class EntityLightningSigil extends EntityMagicConstruct { if(secondaryTarget != target && this.isValidTarget(secondaryTarget)){ - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(target.posX, target.posY + target.height / 2, target.posZ, - secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, + if(world.isRemote){ + + ParticleBuilder.create(Type.LIGHTNING).entity(target) + .pos(0, target.height/2, 0).target(secondaryTarget).spawn(world); + + ParticleBuilder.spawnShockParticles(world, secondaryTarget.posX, + secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2, secondaryTarget.posZ); - world.spawnEntity(arc); - }else{ - for(int k = 0; k < 8; k++){ - ParticleBuilder.create(Type.SPARK) - .pos(secondaryTarget.posX + world.rand.nextFloat() - 0.5, - secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2 + world.rand.nextFloat() * 2 - 1, - secondaryTarget.posZ + world.rand.nextFloat() - 0.5) - .spawn(world); - world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, - secondaryTarget.posX + world.rand.nextFloat() - 0.5, - secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2 - + world.rand.nextFloat() * 2 - 1, - secondaryTarget.posZ + world.rand.nextFloat() - 0.5, 0, 0, 0); - } } secondaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F, diff --git a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java index f53c2b54..a2c6248c 100644 --- a/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java +++ b/src/main/java/electroblob/wizardry/entity/construct/EntityTornado.java @@ -140,12 +140,14 @@ public class EntityTornado extends EntityMagicConstruct { if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) type = Type.SNOW; - double yPos1 = rand.nextDouble() * 8; - ParticleBuilder.create(type) - .pos(this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, - this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d)) - .lifetime(40 + rand.nextInt(10)) - .spawn(world); + if(type != null){ + double yPos1 = rand.nextDouble() * 8; + ParticleBuilder.create(type) + .pos(this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, + this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d)) + .time(40 + rand.nextInt(10)) + .spawn(world); + } } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java index 38665937..1444d6f9 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityDecoy.java @@ -41,14 +41,17 @@ public class EntityDecoy extends EntitySummonedCreature { @Override public void onDespawn(){ super.onDespawn(); - for(int i = 0; i < 20; i++){ - ParticleBuilder.create(Type.DUST) - .pos(this.posX + (this.rand.nextDouble() - 0.5) * this.width, this.getEntityBoundingBox().minY - + this.rand.nextDouble() * this.height, this.posZ + (this.rand.nextDouble() - 0.5) * this.width) - .lifetime(40) - .colour(0.2f, 1.0f, 0.8f) - .shaded(true) - .spawn(world); + + if(world.isRemote){ + for(int i = 0; i < 20; i++){ + ParticleBuilder.create(Type.DUST) + .pos(this.posX + (this.rand.nextDouble() - 0.5) * this.width, this.getEntityBoundingBox().minY + + this.rand.nextDouble() * this.height, this.posZ + (this.rand.nextDouble() - 0.5) * this.width) + .time(40) + .clr(0.2f, 1.0f, 0.8f) + .shaded(true) + .spawn(world); + } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java index 00b4d2e2..356281ea 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityEvilWizard.java @@ -221,7 +221,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity // 0.5F. double y = (double)((float)this.posY - 0.5F + rand.nextFloat()); double z = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1F, 0).colour(1, 1, 0.3f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1F, 0).clr(1, 1, 0.3f).spawn(world); } }else{ if(this.getHealth() < 10){ diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java index 93e25d2b..8003f7f8 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceGiant.java @@ -99,8 +99,8 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature if(this.world.isRemote){ for(int i = 0; i < 30; i++){ float brightness = 0.5f + (rand.nextFloat() / 2); - ParticleBuilder.create(Type.SPARKLE, this).vel(0, -0.02, 0).lifetime(12 + rand.nextInt(8)) - .colour(brightness, brightness + 0.1f, 1.0f).spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).vel(0, -0.02, 0).time(12 + rand.nextInt(8)) + .clr(brightness, brightness + 0.1f, 1.0f).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java index 3f2c07e1..5d9fee8b 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityIceWraith.java @@ -51,8 +51,8 @@ public class EntityIceWraith extends EntityBlazeMinion { .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + this.height / 2 - 0.5d + rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble()) .vel(0, 0.05f, 0) - .lifetime(20 + rand.nextInt(10)) - .colour(brightness, brightness + 0.1f, 1.0f) + .time(20 + rand.nextInt(10)) + .clr(brightness, brightness + 0.1f, 1.0f) .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java index fb5364e8..a97c52af 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityLightningWraith.java @@ -40,8 +40,8 @@ public class EntityLightningWraith extends EntityBlazeMinion { if(this.world.isRemote){ for(int i = 0; i < 15; i++){ float brightness = 0.3f + (rand.nextFloat() / 2); - ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) - .colour(brightness, brightness + 0.2f, 1.0f).spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).time(20 + rand.nextInt(10)) + .clr(brightness, brightness + 0.2f, 1.0f).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java index b182af36..d09a3326 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityShadowWraith.java @@ -125,8 +125,8 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell if(this.world.isRemote){ for(int i = 0; i < 15; i++){ float brightness = rand.nextFloat() * 0.4f; - ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) - .colour(brightness, 0.0f, brightness).spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).time(20 + rand.nextInt(10)) + .clr(brightness, 0.0f, brightness).spawn(world); } } } @@ -160,10 +160,10 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell float brightness = rand.nextFloat() * 0.2f; - ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) - .colour(brightness, 0.0f, brightness).spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).time(20 + rand.nextInt(10)) + .clr(brightness, 0.0f, brightness).spawn(world); - ParticleBuilder.create(Type.DARK_MAGIC, this).colour(0.1f, 0.0f, 0.0f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC, this).clr(0.1f, 0.0f, 0.0f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java index b2a2c8fa..e0275389 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySilverfishMinion.java @@ -82,7 +82,7 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone for(int i = 0; i < 15; i++){ ParticleBuilder.create(Type.DARK_MAGIC) .pos(this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat()) - .colour(0.3f, 0.3f, 0.3f) + .clr(0.3f, 0.3f, 0.3f) .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java index 23b7824b..328e988c 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiderMinion.java @@ -110,7 +110,7 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre for(int i = 0; i < 15; i++){ ParticleBuilder.create(Type.DARK_MAGIC) .pos(this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat()) - .colour(0.1f, 0.2f, 0.0f) + .clr(0.1f, 0.2f, 0.0f) .spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java index efd656d0..67284bde 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritHorse.java @@ -120,7 +120,7 @@ public class EntitySpiritHorse extends EntityHorse { double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).clr(0.8f, 0.8f, 1.0f).spawn(world); } } @@ -158,7 +158,7 @@ public class EntitySpiritHorse extends EntityHorse { double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; - ParticleBuilder.create(Type.DUST).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); + ParticleBuilder.create(Type.DUST).pos(x, y, z).clr(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); } // Spirit horse disappears a short time after being dismounted. diff --git a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java index db5c7ab3..f18601f9 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntitySpiritWolf.java @@ -89,7 +89,7 @@ public class EntitySpiritWolf extends EntityWolf { double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).clr(0.8f, 0.8f, 1.0f).spawn(world); } } @@ -103,7 +103,7 @@ public class EntitySpiritWolf extends EntityWolf { double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; - ParticleBuilder.create(Type.DUST).pos(x, y, z).colour(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); + ParticleBuilder.create(Type.DUST).pos(x, y, z).clr(0.8f, 0.8f, 1.0f).shaded(true).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java index 602a6941..29776335 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityStormElemental.java @@ -148,8 +148,9 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe float brightness = rand.nextFloat() * 0.2f; double dy = this.rand.nextDouble() * (double)this.height; - ParticleBuilder.create(Type.SPARKLE_ROTATING).pos(this.posX, this.posY + dy, this.posZ) - .lifetime(20 + rand.nextInt(10)).colour(0, brightness, brightness).radius(0.2f + 0.5f * dy).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(this.posX, this.posY + dy, this.posZ) + .time(20 + rand.nextInt(10)).clr(0, brightness, brightness)//.entity(this) + .spin(0.2 + 0.5 * dy, 0.1 + 0.05 * world.rand.nextDouble()).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java index 7214304e..1e71a7c2 100644 --- a/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java +++ b/src/main/java/electroblob/wizardry/entity/living/EntityWizard.java @@ -310,7 +310,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp // 0.5F. double y = (double)((float)this.posY - 0.5F + rand.nextFloat()); double z = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1F, 0).colour(1, 1, 0.3f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1F, 0).clr(1, 1, 0.3f).spawn(world); } }else{ if(this.getHealth() < 10){ diff --git a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java index 1b6a0069..a3bbfcee 100644 --- a/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java +++ b/src/main/java/electroblob/wizardry/entity/living/ISummonedCreature.java @@ -308,7 +308,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData { if(this.hasParticleEffect() && thisEntity.world.isRemote && thisEntity.world.rand.nextInt(8) == 0) ParticleBuilder.create(Type.DARK_MAGIC) .pos(thisEntity.posX, thisEntity.posY + thisEntity.world.rand.nextDouble() * 1.5, thisEntity.posZ) - .colour(0.1f, 0.0f, 0.0f) + .clr(0.1f, 0.0f, 0.0f) .spawn(thisEntity.world); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java index 43e81c5e..d9aee1e5 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDarknessOrb.java @@ -47,10 +47,10 @@ public class EntityDarknessOrb extends EntityMagicProjectile { float brightness = rand.nextFloat() * 0.2f; - ParticleBuilder.create(Type.SPARKLE, this).lifetime(20 + rand.nextInt(10)) - .colour(brightness, 0.0f, brightness).spawn(world); + ParticleBuilder.create(Type.SPARKLE, this).time(20 + rand.nextInt(10)) + .clr(brightness, 0.0f, brightness).spawn(world); - ParticleBuilder.create(Type.DARK_MAGIC, this).colour(0.1f, 0.0f, 0.0f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC, this).clr(0.1f, 0.0f, 0.0f).spawn(world); } if(this.ticksExisted > 150){ diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java index 1ab9c0f0..146b0c4e 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityDart.java @@ -36,7 +36,7 @@ public class EntityDart extends EntityMagicArrow { @Override public void tickInAir(){ if(this.world.isRemote){ - ParticleBuilder.create(Type.LEAF, this).lifetime(10 + rand.nextInt(5)).spawn(world); + ParticleBuilder.create(Type.LEAF, this).time(10 + rand.nextInt(5)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java index d6e207c5..32c42bf3 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityFirebomb.java @@ -39,16 +39,19 @@ public class EntityFirebomb extends EntityBomb { // Particle effect if(world.isRemote){ - this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); - + ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(1, 0.6f, 0) + .spawn(world); + for(int i = 0; i < 60 * blastMultiplier; i++){ ParticleBuilder.create(Type.MAGIC_FIRE, rand, posX, posY, posZ, 2*blastMultiplier, false) - .lifetime(15 + rand.nextInt(5)).scale(2 + rand.nextFloat()).spawn(world); + .time(15 + rand.nextInt(5)).scale(2 + rand.nextFloat()).spawn(world); ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) - .colour(1.0f, 0.2f + rand.nextFloat() * 0.4f, 0.0f).spawn(world); + .clr(1.0f, 0.2f + rand.nextFloat() * 0.4f, 0.0f).spawn(world); } + + this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); } if(!this.world.isRemote){ diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java index 89738294..8fcf251d 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceArrow.java @@ -1,6 +1,8 @@ package electroblob.wizardry.entity.projectile; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; import net.minecraft.world.World; @@ -15,6 +17,8 @@ public class EntityForceArrow extends EntityMagicArrow { @Override public void onEntityHit(EntityLivingBase entityHit){ this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); + if(this.world.isRemote) + ParticleBuilder.create(Type.FLASH).pos(posX, posY, posZ).scale(1.3f).clr(0.75f, 1, 0.85f).spawn(world); } @Override @@ -25,6 +29,13 @@ public class EntityForceArrow extends EntityMagicArrow { @Override public void onBlockHit(){ this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); + if(this.world.isRemote){ + // Gets a position slightly away from the block hit so the particle doesn't get cut in half by the block face + Vec3d vec = hit.hitVec.add(new Vec3d(hit.sideHit.getDirectionVec()).scale(0.15)); + ParticleBuilder.create(Type.FLASH).pos(vec).scale(1.3f).clr(0.75f, 1, 0.85f).spawn(world); + vec = hit.hitVec.add(new Vec3d(hit.sideHit.getDirectionVec()).scale(WizardryUtilities.ANTI_Z_FIGHTING_OFFSET)); + ParticleBuilder.create(Type.SCORCH).pos(vec).face(hit.sideHit).clr(0, 1, 0.5f).spawn(world); + } } @Override diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java index 5c554aa2..73373a40 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityForceOrb.java @@ -31,8 +31,8 @@ public class EntityForceOrb extends EntityBomb { if(this.world.isRemote){ for(int j = 0; j < 20; j++){ float brightness = 0.5f + (rand.nextFloat() / 2); - ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.25, true).lifetime(6) - .colour(brightness, 1.0f, brightness + 0.2f).spawn(world); + ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.25, true).time(6) + .clr(brightness, 1.0f, brightness + 0.2f).spawn(world); } this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java index 25282d28..1f35f8d6 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceCharge.java @@ -47,11 +47,11 @@ public class EntityIceCharge extends EntityBomb { for(int i = 0; i < 30 * blastMultiplier; i++){ ParticleBuilder.create(Type.ICE, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) - .lifetime(35).gravity(true).spawn(world); + .time(35).gravity(true).spawn(world); float brightness = 0.4f + rand.nextFloat() * 0.5f; ParticleBuilder.create(Type.DARK_MAGIC, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) - .colour(brightness, brightness + 0.1f, 1.0f).spawn(world); + .clr(brightness, brightness + 0.1f, 1.0f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java index 5666ca18..1863f343 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceLance.java @@ -46,7 +46,7 @@ public class EntityIceLance extends EntityMagicArrow { if(this.world.isRemote){ for(int j = 0; j < 10; j++){ ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) - .lifetime(20 + rand.nextInt(10)).gravity(true).spawn(world); + .time(20 + rand.nextInt(10)).gravity(true).spawn(world); } } // Parameters for sound: sound event name, volume, pitch. diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java index 936acacc..c4d42bfa 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityIceShard.java @@ -41,9 +41,13 @@ public class EntityIceShard extends EntityMagicArrow { public void onBlockHit(){ // Adds a particle effect when the ice shard hits a block. if(this.world.isRemote){ + // Gets a position slightly away from the block hit so the particle doesn't get cut in half by the block face + Vec3d vec = hit.hitVec.add(new Vec3d(hit.sideHit.getDirectionVec()).scale(0.15)); + ParticleBuilder.create(Type.FLASH).pos(vec).clr(0.75f, 1, 1).spawn(world); + for(int j = 0; j < 10; j++){ ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) - .lifetime(20 + rand.nextInt(10)).gravity(true).spawn(world); + .time(20 + rand.nextInt(10)).gravity(true).spawn(world); } } // Parameters for sound: sound event name, volume, pitch. diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java index 8e5d38dc..63857276 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityLightningArrow.java @@ -32,6 +32,12 @@ public class EntityLightningArrow extends EntityMagicArrow { } this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.0F); + @Override + public void onBlockHit(RayTraceResult hit){ + if(this.world.isRemote){ + Vec3d vec = hit.hitVec.add(new Vec3d(hit.sideHit.getDirectionVec()).scale(WizardryUtilities.ANTI_Z_FIGHTING_OFFSET)); + ParticleBuilder.create(Type.SCORCH).pos(vec).face(hit.sideHit).clr(0.4f, 0.8f, 1).scale(0.6f).spawn(world); + } } @Override diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java index bf2e5166..0485db50 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicArrow.java @@ -201,8 +201,10 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE /** Called when the projectile hits an entity. Override to add potion effects and such like. */ protected void onEntityHit(EntityLivingBase entityHit){} - /** Called when the projectile hits a block. Override to add sound effects and such like. */ - protected void onBlockHit(){} + /** Called when the projectile hits a block. Override to add sound effects and such like. + * @param hit A vector representing the exact coordinates of the hit; use this to centre particle effects, for + * example. */ + protected void onBlockHit(RayTraceResult hit){} @Override public void onUpdate(){ @@ -390,7 +392,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE this.inGround = true; this.arrowShake = 7; - this.onBlockHit(); + this.onBlockHit(raytraceresult); if(this.stuckInBlock.getMaterial() != Material.AIR){ this.stuckInBlock.getBlock().onEntityCollidedWithBlock(this.world, raytraceresult.getBlockPos(), diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java index 60a3e60b..676ba719 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityMagicMissile.java @@ -4,9 +4,14 @@ import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder.Type; import net.minecraft.entity.EntityLivingBase; import net.minecraft.init.SoundEvents; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class EntityMagicMissile extends EntityMagicArrow { + + /** The number of ticks the magic missile flies for before vanishing; effectively determines its range. */ + private static final int LIFETIME = 12; /** Creates a new magic missile in the given world. */ public EntityMagicMissile(World world){ @@ -26,25 +31,32 @@ public class EntityMagicMissile extends EntityMagicArrow { } @Override - public void onBlockHit(){ - if(this.world.isRemote) spawnImpactParticles(); - } - - private void spawnImpactParticles(){ - ParticleBuilder.create(Type.FLASH).pos(posX, posY, posZ).colour(0.5f + rand.nextFloat()/2, 0.5f + rand.nextFloat()/2, - 0.5f + rand.nextFloat()/2).spawn(world); + public void onBlockHit(RayTraceResult hit){ + if(this.world.isRemote){ + // Gets a position slightly away from the block hit so the particle doesn't get cut in half by the block face + Vec3d vec = hit.hitVec.add(new Vec3d(hit.sideHit.getDirectionVec()).scale(0.15)); + ParticleBuilder.create(Type.FLASH).pos(vec).clr(1, 1, 0.65f).fade(0.85f, 0.5f, 0.8f).spawn(world); + } } @Override public void tickInAir(){ - if(this.ticksExisted > 20){ + if(this.ticksExisted > LIFETIME){ this.setDead(); } if(this.world.isRemote){ - ParticleBuilder.create(Type.SPARKLE).pos(this.posX, this.posY, this.posZ).lifetime(20 + rand.nextInt(10)) - .colour(0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2)).spawn(world); + ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1) + .time(20 + rand.nextInt(10)).spawn(world); + + if(this.ticksExisted > 1){ // Don't spawn particles behind where it started! + double x = posX - motionX/2; + double y = posY - motionY/2; + double z = posZ - motionZ/2; + ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1) + .time(20 + rand.nextInt(10)).spawn(world); + } } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java index c2ae3d54..5dfd2f8e 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntityPoisonBomb.java @@ -41,13 +41,17 @@ public class EntityPoisonBomb extends EntityBomb { // Particle effect if(world.isRemote){ + + ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier) + .clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); + for(int i = 0; i < 60 * blastMultiplier; i++){ - ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).lifetime(35) - .colour(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); + ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).time(35) + .clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) - .colour(0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world); + .clr(0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world); } // Spawning this after the other particles fixes the rendering colour bug. It's a bit of a cheat, but it // works pretty well. diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java index 61dcf727..e19592a6 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySmokeBomb.java @@ -27,7 +27,11 @@ public class EntitySmokeBomb extends EntityBomb { // Particle effect if(world.isRemote){ + + ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(0, 0, 0).spawn(world); + this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); + for(int i = 0; i < 60 * blastMultiplier; i++){ this.world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, @@ -37,7 +41,7 @@ public class EntitySmokeBomb extends EntityBomb { float brightness = rand.nextFloat() * 0.3f; ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) - .colour(brightness, brightness, brightness).spawn(world); + .clr(brightness, brightness, brightness).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java index 6b8a92b1..28ddbf8a 100644 --- a/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java +++ b/src/main/java/electroblob/wizardry/entity/projectile/EntitySparkBomb.java @@ -2,11 +2,11 @@ package electroblob.wizardry.entity.projectile; import java.util.List; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; @@ -65,19 +65,14 @@ public class EntitySparkBomb extends EntityBomb { if(!this.world.isRemote){ - EntityArc arc = new EntityArc(this.world); - arc.setEndpointCoords(this.posX, this.posY, this.posZ, target.posX, target.posY + target.height / 2, - target.posZ); - this.world.spawnEntity(arc); - - target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); + target.playSound(WizardrySounds.ENTITY_SPARK_BOMB_CHAIN, 1.0F, rand.nextFloat() * 0.4F + 1.5F); target.attackEntityFrom( MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), 5.0f * damageMultiplier); }else{ - // Particle effect + ParticleBuilder.create(Type.LIGHTNING).pos(this.getPositionVector()).target(target).spawn(world); ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); } } diff --git a/src/main/java/electroblob/wizardry/potion/PotionFrost.java b/src/main/java/electroblob/wizardry/potion/PotionFrost.java index 7cb709e2..2733ded4 100644 --- a/src/main/java/electroblob/wizardry/potion/PotionFrost.java +++ b/src/main/java/electroblob/wizardry/potion/PotionFrost.java @@ -40,7 +40,6 @@ public class PotionFrost extends Potion implements ICustomPotionParticles { @Override public void spawnCustomParticle(World world, double x, double y, double z){ - ParticleBuilder.create(Type.SNOW).pos(x, y, z).lifetime(15 + world.rand.nextInt(5)).spawn(world); } @Override @@ -55,6 +54,7 @@ public class PotionFrost extends Potion implements ICustomPotionParticles { public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha){ mc.renderEngine.bindTexture(ICON); WizardryUtilities.drawTexturedRect(x + 3, y + 3, 0, 0, 18, 18, 18, 18); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).time(15 + world.rand.nextInt(5)).spawn(world); } @SubscribeEvent diff --git a/src/main/java/electroblob/wizardry/spell/Arc.java b/src/main/java/electroblob/wizardry/spell/Arc.java index 296b3355..e543790d 100644 --- a/src/main/java/electroblob/wizardry/spell/Arc.java +++ b/src/main/java/electroblob/wizardry/spell/Arc.java @@ -30,11 +30,10 @@ public class Arc extends SpellRay { if(WizardryUtilities.isLiving(target)){ - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + 1, caster.posZ, target.posX, target.posY + target.height / 2, target.posZ); - world.spawnEntity(arc); - }else{ + if(world.isRemote){ + // Rather neatly, the entity can be set here and if it's null nothing will happen. + ParticleBuilder.create(Type.LIGHTNING).entity(caster) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world); ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); } diff --git a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java index 650e1966..099943c5 100644 --- a/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java +++ b/src/main/java/electroblob/wizardry/spell/ArcaneJammer.java @@ -60,7 +60,7 @@ public class ArcaneJammer extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.9f, 0.3f, 0.7f) + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0.9f, 0.3f, 0.7f) .spawn(world); } diff --git a/src/main/java/electroblob/wizardry/spell/Banish.java b/src/main/java/electroblob/wizardry/spell/Banish.java index 469334a2..f1523866 100644 --- a/src/main/java/electroblob/wizardry/spell/Banish.java +++ b/src/main/java/electroblob/wizardry/spell/Banish.java @@ -89,7 +89,7 @@ public class Banish extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ world.spawnParticle(EnumParticleTypes.PORTAL, x, y - 0.5, z, 0, 0, 0); - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.2f, 0, 0.2f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.2f, 0, 0.2f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/ChainLightning.java b/src/main/java/electroblob/wizardry/spell/ChainLightning.java index ca23af59..8e6bfb72 100644 --- a/src/main/java/electroblob/wizardry/spell/ChainLightning.java +++ b/src/main/java/electroblob/wizardry/spell/ChainLightning.java @@ -102,12 +102,11 @@ public class ChainLightning extends SpellRay { target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); } - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.getEntityBoundingBox().minY + caster.height / 2, caster.posZ, - target.posX, target.getEntityBoundingBox().minY + target.height / 2, target.posZ); - world.spawnEntity(arc); - }else{ + if(world.isRemote){ + + ParticleBuilder.create(Type.LIGHTNING).entity(caster) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world); + ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); } diff --git a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java index 6f74e00a..0b582f15 100644 --- a/src/main/java/electroblob/wizardry/spell/Clairvoyance.java +++ b/src/main/java/electroblob/wizardry/spell/Clairvoyance.java @@ -127,7 +127,7 @@ public class Clairvoyance extends Spell { (nextPoint.x - point.x) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.y - point.y) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.z - point.z) / (float)PARTICLE_MOVEMENT_INTERVAL) - .lifetime((int)(1800 * durationMultiplier)).colour(0, 1, 0.3f).spawn(world); + .time((int)(1800 * durationMultiplier)).clr(0, 1, 0.3f).spawn(world); path.incrementPathIndex(); path.incrementPathIndex(); @@ -136,7 +136,7 @@ public class Clairvoyance extends Spell { point = path.getFinalPathPoint(); ParticleBuilder.create(Type.PATH).pos(point.x + 0.5, point.y + 0.5, point.z + 0.5) - .lifetime((int)(1800 * durationMultiplier)).colour(1, 1, 1).spawn(world); + .time((int)(1800 * durationMultiplier)).clr(1, 1, 1).spawn(world); } @SubscribeEvent diff --git a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java index 4936395a..d6e73fb2 100644 --- a/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java +++ b/src/main/java/electroblob/wizardry/spell/CurseOfSoulbinding.java @@ -54,9 +54,9 @@ public class CurseOfSoulbinding extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.4f, 0, 0).spawn(world); - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(1, 0.8f, 1).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.4f, 0, 0).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(1, 0.8f, 1).spawn(world); } @SubscribeEvent diff --git a/src/main/java/electroblob/wizardry/spell/Entrapment.java b/src/main/java/electroblob/wizardry/spell/Entrapment.java index 2b7f8c30..931a230e 100644 --- a/src/main/java/electroblob/wizardry/spell/Entrapment.java +++ b/src/main/java/electroblob/wizardry/spell/Entrapment.java @@ -63,7 +63,7 @@ public class Entrapment extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ world.spawnParticle(EnumParticleTypes.PORTAL, x, y - 0.5, z, 0, 0, 0); - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0, 0).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java index f157a8c2..1c940d4e 100644 --- a/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FlamingWeapon.java @@ -53,7 +53,7 @@ public class FlamingWeapon extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.9f, 0.7f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(0.9f, 0.7f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Flight.java b/src/main/java/electroblob/wizardry/spell/Flight.java index 70183b00..eb36ceff 100644 --- a/src/main/java/electroblob/wizardry/spell/Flight.java +++ b/src/main/java/electroblob/wizardry/spell/Flight.java @@ -41,11 +41,11 @@ public class Flight extends Spell { double x = caster.posX - 1 + world.rand.nextDouble() * 2; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ - 1 + world.rand.nextDouble() * 2; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(0.8f, 1, 0.5f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(0.8f, 1, 0.5f).spawn(world); x = caster.posX - 1 + world.rand.nextDouble() * 2; y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); z = caster.posZ - 1 + world.rand.nextDouble() * 2; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(1, 1, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(1, 1, 1).spawn(world); } if(ticksInUse % 24 == 0){ diff --git a/src/main/java/electroblob/wizardry/spell/FontOfMana.java b/src/main/java/electroblob/wizardry/spell/FontOfMana.java index df6f46af..6963c42f 100644 --- a/src/main/java/electroblob/wizardry/spell/FontOfMana.java +++ b/src/main/java/electroblob/wizardry/spell/FontOfMana.java @@ -52,8 +52,8 @@ public class FontOfMana extends Spell { double y = caster.getEntityBoundingBox().minY; double z = caster.posZ + radius * Math.sin(angle); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).lifetime(50) - .colour(1, 1 - hue, 0.6f + hue).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50) + .clr(1, 1 - hue, 0.6f + hue).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java index e08bd145..0cd51ef4 100644 --- a/src/main/java/electroblob/wizardry/spell/ForestsCurse.java +++ b/src/main/java/electroblob/wizardry/spell/ForestsCurse.java @@ -50,13 +50,13 @@ public class ForestsCurse extends SpellAreaEffect { float brightness = world.rand.nextFloat() / 4; ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).vel(0, -0.2, 0) - .colour(0.05f + brightness, 0.2f + brightness, 0).spawn(world); + .clr(0.05f + brightness, 0.2f + brightness, 0).spawn(world); brightness = world.rand.nextFloat() / 4; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.05, 0).lifetime(50) - .colour(0.1f + brightness, 0.2f + brightness, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.05, 0).time(50) + .clr(0.1f + brightness, 0.2f + brightness, 0).spawn(world); - ParticleBuilder.create(Type.LEAF).pos(x, y, z).vel(0, -0.01, 0).lifetime(40 + world.rand.nextInt(12)).spawn(world); + ParticleBuilder.create(Type.LEAF).pos(x, y, z).vel(0, -0.01, 0).time(40 + world.rand.nextInt(12)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Freeze.java b/src/main/java/electroblob/wizardry/spell/Freeze.java index 48f19bb0..3347b566 100644 --- a/src/main/java/electroblob/wizardry/spell/Freeze.java +++ b/src/main/java/electroblob/wizardry/spell/Freeze.java @@ -87,8 +87,8 @@ public class Freeze extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ float brightness = 0.5f + (world.rand.nextFloat() / 2); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)) - .colour(brightness, brightness + 0.1f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)) + .clr(brightness, brightness + 0.1f, 1).spawn(world); ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world); } diff --git a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java index e2792eb9..19b8a8bc 100644 --- a/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/FreezingWeapon.java @@ -59,7 +59,7 @@ public class FreezingWeapon extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.9f, 0.7f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(0.9f, 0.7f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/FrostRay.java b/src/main/java/electroblob/wizardry/spell/FrostRay.java index 1a360880..47c36b37 100644 --- a/src/main/java/electroblob/wizardry/spell/FrostRay.java +++ b/src/main/java/electroblob/wizardry/spell/FrostRay.java @@ -104,9 +104,9 @@ public class FrostRay extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ float brightness = world.rand.nextFloat(); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)) - .colour(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); - ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)) + .clr(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Glide.java b/src/main/java/electroblob/wizardry/spell/Glide.java index 0db03cca..7821c800 100644 --- a/src/main/java/electroblob/wizardry/spell/Glide.java +++ b/src/main/java/electroblob/wizardry/spell/Glide.java @@ -35,11 +35,11 @@ public class Glide extends Spell { double x = caster.posX - 0.25 + world.rand.nextDouble() / 2; double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); double z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(1, 1, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(1, 1, 1).spawn(world); x = caster.posX - 0.25 + world.rand.nextDouble() / 2; y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; - ParticleBuilder.create(Type.LEAF).pos(x, y, z).lifetime(20).spawn(world); + ParticleBuilder.create(Type.LEAF).pos(x, y, z).time(20).spawn(world); } if(ticksInUse % 24 == 0){ diff --git a/src/main/java/electroblob/wizardry/spell/GroupHeal.java b/src/main/java/electroblob/wizardry/spell/GroupHeal.java index 58030155..71593ec1 100644 --- a/src/main/java/electroblob/wizardry/spell/GroupHeal.java +++ b/src/main/java/electroblob/wizardry/spell/GroupHeal.java @@ -9,8 +9,8 @@ import electroblob.wizardry.constants.Tier; import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; -import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; @@ -49,10 +49,10 @@ public class GroupHeal extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(1, 1, 0.3f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(1, 1, 0.3f).spawn(world); } - - Wizardry.proxy.spawnEntityParticle(world, caster, 15, 1, 1, 0.3f); + + ParticleBuilder.create(Type.BUFF).entity(caster).clr(1, 1, 0.3f).spawn(world); } WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, @@ -78,10 +78,10 @@ public class GroupHeal extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(1, 1, 0.3f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(1, 1, 0.3f).spawn(world); } - - Wizardry.proxy.spawnEntityParticle(world, caster, 15, 1, 1, 0.3f); + + ParticleBuilder.create(Type.BUFF).entity(caster).clr(1, 1, 0.3f).spawn(world); } WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F, diff --git a/src/main/java/electroblob/wizardry/spell/HealAlly.java b/src/main/java/electroblob/wizardry/spell/HealAlly.java index f6ccdb65..e36ab8eb 100644 --- a/src/main/java/electroblob/wizardry/spell/HealAlly.java +++ b/src/main/java/electroblob/wizardry/spell/HealAlly.java @@ -41,10 +41,10 @@ public class HealAlly extends SpellRay { double x1 = (double)((float)entity.posX + world.rand.nextFloat() * 2 - 1.0f); double y1 = (double)((float)entity.getEntityBoundingBox().minY + entity.getEyeHeight() - 0.5f + world.rand.nextFloat()); double z1 = (double)((float)entity.posZ + world.rand.nextFloat() * 2 - 1.0f); - ParticleBuilder.create(Type.SPARKLE).pos(x1, y1, z1).vel(0, 0.1F, 0).colour(r, g, b).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x1, y1, z1).vel(0, 0.1F, 0).clr(r, g, b).spawn(world); } - - Wizardry.proxy.spawnEntityParticle(world, entity, 15, r, g, b); + + ParticleBuilder.create(Type.BUFF).entity(caster).clr(r, g, b).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/IceStatue.java b/src/main/java/electroblob/wizardry/spell/IceStatue.java index 2132ef16..9c5b1cfd 100644 --- a/src/main/java/electroblob/wizardry/spell/IceStatue.java +++ b/src/main/java/electroblob/wizardry/spell/IceStatue.java @@ -55,9 +55,9 @@ public class IceStatue extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ float brightness = 0.5f + world.rand.nextFloat() * 0.5f; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)) - .colour(brightness, brightness + 0.1f, 1.0f).spawn(world); - ParticleBuilder.create(Type.SNOW).pos(x, y, z).lifetime(20 + world.rand.nextInt(10)).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)) + .clr(brightness, brightness + 0.1f, 1.0f).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).time(20 + world.rand.nextInt(10)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java index caf3f92e..ec1178fd 100644 --- a/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java +++ b/src/main/java/electroblob/wizardry/spell/ImbueWeapon.java @@ -68,7 +68,7 @@ public class ImbueWeapon extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.9f, 0.7f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(0.9f, 0.7f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Intimidate.java b/src/main/java/electroblob/wizardry/spell/Intimidate.java index 2d8f6aa4..626c7210 100644 --- a/src/main/java/electroblob/wizardry/spell/Intimidate.java +++ b/src/main/java/electroblob/wizardry/spell/Intimidate.java @@ -68,7 +68,7 @@ public class Intimidate extends Spell { double x = caster.posX - 1 + world.rand.nextDouble() * 2; double y = caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble() * 0.5; double z = caster.posZ - 1 + world.rand.nextDouble() * 2; - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.9f, 0.1f, 0).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.9f, 0.1f, 0).spawn(world); } } WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_GROWL, 1.0f, 1.0f); diff --git a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java index 859a5a90..425e7c3b 100644 --- a/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java +++ b/src/main/java/electroblob/wizardry/spell/InvigoratingPresence.java @@ -53,7 +53,7 @@ public class InvigoratingPresence extends Spell { double y = caster.getEntityBoundingBox().minY; double z = caster.posZ + radius * Math.sin(angle); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).lifetime(50).colour(1, 0.2f, 0.2f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50).clr(1, 0.2f, 0.2f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java index e2773b79..71ce3368 100644 --- a/src/main/java/electroblob/wizardry/spell/InvokeWeather.java +++ b/src/main/java/electroblob/wizardry/spell/InvokeWeather.java @@ -54,7 +54,7 @@ public class InvokeWeather extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.5f, 0.7f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(0.5f, 0.7f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Levitation.java b/src/main/java/electroblob/wizardry/spell/Levitation.java index 34779ce6..60e16ab8 100644 --- a/src/main/java/electroblob/wizardry/spell/Levitation.java +++ b/src/main/java/electroblob/wizardry/spell/Levitation.java @@ -30,7 +30,7 @@ public class Levitation extends Spell { double x = caster.posX - 0.25 + world.rand.nextDouble() * 0.5; double y = caster.getEntityBoundingBox().minY; double z = caster.posZ - 0.25 + world.rand.nextDouble() * 0.5; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).lifetime(15).colour(0.5f, 1, 0.7f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.1, 0).time(15).clr(0.5f, 1, 0.7f).spawn(world); } if(ticksInUse % 24 == 0 && world.isRemote){ Wizardry.proxy.playMovingSound(caster, WizardrySounds.SPELL_LOOP_SPARKLE, 0.5f, 1, false); diff --git a/src/main/java/electroblob/wizardry/spell/LifeDrain.java b/src/main/java/electroblob/wizardry/spell/LifeDrain.java index 364b5890..b60109f9 100644 --- a/src/main/java/electroblob/wizardry/spell/LifeDrain.java +++ b/src/main/java/electroblob/wizardry/spell/LifeDrain.java @@ -89,10 +89,10 @@ public class LifeDrain extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - if(world.rand.nextInt(5) == 0) ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); + if(world.rand.nextInt(5) == 0) ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0, 0).spawn(world); // This used to multiply the velocity by the distance from the caster - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(6)) - .colour(0.5f, 0, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(6)) + .clr(0.5f, 0, 0).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/LightningPulse.java b/src/main/java/electroblob/wizardry/spell/LightningPulse.java index acd809d4..69c1543b 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningPulse.java +++ b/src/main/java/electroblob/wizardry/spell/LightningPulse.java @@ -5,11 +5,12 @@ import java.util.List; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.construct.EntityLightningPulse; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; +import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLivingBase; @@ -72,14 +73,10 @@ public class LightningPulse extends Spell { } } - if(!world.isRemote){ - // Surely neither of the commented lines would have done anything? - EntityLightningPulse lightningpulse = new EntityLightningPulse(world); - lightningpulse.setPosition(caster.posX, caster.getEntityBoundingBox().minY, caster.posZ); - //lightningpulse.setCaster(caster); - lightningpulse.lifetime = 7; - //lightningpulse.damageMultiplier = modifiers.get(SpellModifiers.POTENCY); - world.spawnEntity(lightningpulse); + if(world.isRemote){ + ParticleBuilder.create(Type.LIGHTNING_PULSE).pos(caster.posX, caster.getEntityBoundingBox().minY + + WizardryUtilities.ANTI_Z_FIGHTING_OFFSET, caster.posZ) + .scale(modifiers.get(WizardryItems.blast_upgrade)).spawn(world); } caster.swingArm(hand); diff --git a/src/main/java/electroblob/wizardry/spell/LightningRay.java b/src/main/java/electroblob/wizardry/spell/LightningRay.java index de680000..3521b3d5 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningRay.java +++ b/src/main/java/electroblob/wizardry/spell/LightningRay.java @@ -3,7 +3,6 @@ package electroblob.wizardry.spell; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; @@ -18,6 +17,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; @@ -71,23 +71,18 @@ public class LightningRay extends SpellRay { BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); } - if(!world.isRemote){ + if(world.isRemote){ + + if(ticksInUse % 3 == 0) ParticleBuilder.create(Type.LIGHTNING).entity(caster) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world); - if(ticksInUse % 2 == 0){ - - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, target.posX, - target.posY + target.height / 2, target.posZ); - arc.lifetime = 1; - world.spawnEntity(arc); - } - - }else{ // Particle effect for(int i=0; i<5; i++){ ParticleBuilder.create(Type.SPARK, target).spawn(world); } } + + return true; } return false; @@ -101,21 +96,15 @@ public class LightningRay extends SpellRay { @Override protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ // This is a nice example of when onMiss is used for more than just returning a boolean - if(!world.isRemote){ + if(world.isRemote && ticksInUse % 4 == 0){ - if(ticksInUse % 2 == 0){ - - double freeRange = 0.8 * baseRange; // The arc does not reach full range when it has a free end - - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, - caster.posX + caster.getLookVec().x * freeRange, - caster.posY + caster.getEyeHeight() + caster.getLookVec().y * freeRange, - caster.posZ + caster.getLookVec().z * freeRange); - arc.lifetime = 1; - world.spawnEntity(arc); - - } + if(caster != null) origin = origin.subtract(0, Y_OFFSET, 0); + + double freeRange = 0.8 * baseRange; // The arc does not reach full range when it has a free end + Vec3d endpoint = origin.add(direction.scale(freeRange)); + + ParticleBuilder.create(Type.LIGHTNING).entity(caster) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(endpoint).spawn(world); } return true; diff --git a/src/main/java/electroblob/wizardry/spell/LightningWeb.java b/src/main/java/electroblob/wizardry/spell/LightningWeb.java index 72b2cc67..8f5f1256 100644 --- a/src/main/java/electroblob/wizardry/spell/LightningWeb.java +++ b/src/main/java/electroblob/wizardry/spell/LightningWeb.java @@ -5,7 +5,6 @@ import java.util.List; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; @@ -20,6 +19,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; @@ -119,19 +119,20 @@ public class LightningWeb extends SpellRay { @Override protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ // This is a nice example of when onMiss is used for more than just returning a boolean - if(!world.isRemote){ + if(world.isRemote){ + + if(caster != null) origin = origin.subtract(0, Y_OFFSET, 0); + + double freeRange = 0.8 * baseRange; // The arc does not reach full range when it has a free end + Vec3d endpoint = origin.add(direction.scale(freeRange)); + + ParticleBuilder.create(Type.BEAM).entity(caster).clr(0.2f, 0.6f, 1) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(endpoint).spawn(world); if(ticksInUse % 2 == 0){ - - double freeRange = 0.8 * baseRange; // The arc does not reach full range when it has a free end - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, - caster.posX + caster.getLookVec().x * freeRange, - caster.posY + caster.getEyeHeight() + caster.getLookVec().y * freeRange, - caster.posZ + caster.getLookVec().z * freeRange); - arc.lifetime = 1; - world.spawnEntity(arc); + ParticleBuilder.create(Type.LIGHTNING).entity(caster) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(endpoint).spawn(world); } } @@ -150,17 +151,16 @@ public class LightningWeb extends SpellRay { MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); } - if(!world.isRemote){ - // Arc entity spawning - if(ticksInUse % 2 == 0){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(origin.posX, origin.posY + 1.2, origin.posZ, target.posX, - target.posY + target.height / 2, target.posZ); - arc.lifetime = 1; - world.spawnEntity(arc); - } + if(world.isRemote){ - }else{ + ParticleBuilder.create(Type.BEAM).entity(caster).clr(0.2f, 0.6f, 1) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world); + + if(ticksInUse % 3 == 0){ + ParticleBuilder.create(Type.LIGHTNING).entity(caster) + .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world); + } + // Particle effect for(int i=0; i<5; i++){ ParticleBuilder.create(Type.SPARK, target).spawn(world); diff --git a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java index 56ec9107..174e28ef 100644 --- a/src/main/java/electroblob/wizardry/spell/Metamorphosis.java +++ b/src/main/java/electroblob/wizardry/spell/Metamorphosis.java @@ -34,6 +34,7 @@ import net.minecraft.entity.passive.EntityPig; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class Metamorphosis extends SpellRay { @@ -111,7 +112,7 @@ public class Metamorphosis extends SpellRay { }else{ for(int i=0; i<5; i++){ - ParticleBuilder.create(Type.DARK_MAGIC).pos(xPos, yPos, zPos).colour(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(xPos, yPos, zPos).clr(0.1f, 0, 0).spawn(world); } } } diff --git a/src/main/java/electroblob/wizardry/spell/MindControl.java b/src/main/java/electroblob/wizardry/spell/MindControl.java index 96c4cccd..0c10155b 100644 --- a/src/main/java/electroblob/wizardry/spell/MindControl.java +++ b/src/main/java/electroblob/wizardry/spell/MindControl.java @@ -76,10 +76,10 @@ public class MindControl extends SpellRay { for(int i=0; i<10; i++){ ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) - .colour(0.8f, 0.2f, 1.0f).spawn(world); + .clr(0.8f, 0.2f, 1.0f).spawn(world); ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) - .colour(0.2f, 0.04f, 0.25f).spawn(world); + .clr(0.2f, 0.04f, 0.25f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/MindTrick.java b/src/main/java/electroblob/wizardry/spell/MindTrick.java index 0bf6b2fa..739d585f 100644 --- a/src/main/java/electroblob/wizardry/spell/MindTrick.java +++ b/src/main/java/electroblob/wizardry/spell/MindTrick.java @@ -57,7 +57,7 @@ public class MindTrick extends SpellRay { for(int i=0; i<10; i++){ ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) - .colour(0.8f, 0.2f, 1.0f).spawn(world); + .clr(0.8f, 0.2f, 1.0f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Petrify.java b/src/main/java/electroblob/wizardry/spell/Petrify.java index bdbaba16..757d9f29 100644 --- a/src/main/java/electroblob/wizardry/spell/Petrify.java +++ b/src/main/java/electroblob/wizardry/spell/Petrify.java @@ -53,8 +53,8 @@ public class Petrify extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.2f, 0.2f, 0.2f).spawn(world); - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0.1f, 0.1f).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0.2f, 0.2f, 0.2f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0.1f, 0.1f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java index f9f87a10..e1d71f41 100644 --- a/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java +++ b/src/main/java/electroblob/wizardry/spell/PlagueOfDarkness.java @@ -58,12 +58,12 @@ public class PlagueOfDarkness extends Spell { particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); ParticleBuilder.create(Type.DARK_MAGIC).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) - .vel(particleX - caster.posX, 0, particleZ - caster.posZ).colour(0.1f, 0, 0).spawn(world); + .vel(particleX - caster.posX, 0, particleZ - caster.posZ).clr(0.1f, 0, 0).spawn(world); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) - .vel(particleX - caster.posX, 0, particleZ - caster.posZ).lifetime(30).colour(0.1f, 0, 0.05f).spawn(world); + .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.1f, 0, 0.05f).spawn(world); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); diff --git a/src/main/java/electroblob/wizardry/spell/Poison.java b/src/main/java/electroblob/wizardry/spell/Poison.java index 0a81900e..057f0f2c 100644 --- a/src/main/java/electroblob/wizardry/spell/Poison.java +++ b/src/main/java/electroblob/wizardry/spell/Poison.java @@ -68,8 +68,8 @@ public class Poison extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.3f, 0.7f, 0).spawn(world); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.1f, 0.4f, 0).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.3f, 0.7f, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0.1f, 0.4f, 0).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Shockwave.java b/src/main/java/electroblob/wizardry/spell/Shockwave.java index 52bf90a8..5b970204 100644 --- a/src/main/java/electroblob/wizardry/spell/Shockwave.java +++ b/src/main/java/electroblob/wizardry/spell/Shockwave.java @@ -78,12 +78,12 @@ public class Shockwave extends Spell { particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) - .vel(particleX - caster.posX, 0, particleZ - caster.posZ).lifetime(30).colour(0.8f, 0.8f, 1).spawn(world); + .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.8f, 0.8f, 1).spawn(world); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); ParticleBuilder.create(Type.SPARKLE).pos(particleX, caster.getEntityBoundingBox().minY, particleZ) - .vel(particleX - caster.posX, 0, particleZ - caster.posZ).lifetime(30).colour(0.9f, 0.9f, 0.9f).spawn(world); + .vel(particleX - caster.posX, 0, particleZ - caster.posZ).time(30).clr(0.9f, 0.9f, 0.9f).spawn(world); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); diff --git a/src/main/java/electroblob/wizardry/spell/Slime.java b/src/main/java/electroblob/wizardry/spell/Slime.java index 4b04b83d..b972686b 100644 --- a/src/main/java/electroblob/wizardry/spell/Slime.java +++ b/src/main/java/electroblob/wizardry/spell/Slime.java @@ -87,7 +87,7 @@ public class Slime extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ world.spawnParticle(EnumParticleTypes.SLIME, x, y, z, 0, 0, 0); - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.2f, 0.8f, 0.1f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.2f, 0.8f, 0.1f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Snare.java b/src/main/java/electroblob/wizardry/spell/Snare.java index d7e64753..fa2259ea 100644 --- a/src/main/java/electroblob/wizardry/spell/Snare.java +++ b/src/main/java/electroblob/wizardry/spell/Snare.java @@ -54,9 +54,9 @@ public class Snare extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ float brightness = world.rand.nextFloat() * 0.25f; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(20 + world.rand.nextInt(8)) - .colour(brightness, brightness + 0.1f, 0).spawn(world); - ParticleBuilder.create(Type.LEAF).pos(x, y, z).vel(0, -0.01, 0).lifetime(40 + world.rand.nextInt(10)).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(20 + world.rand.nextInt(8)) + .clr(brightness, brightness + 0.1f, 0).spawn(world); + ParticleBuilder.create(Type.LEAF).pos(x, y, z).vel(0, -0.01, 0).time(40 + world.rand.nextInt(10)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/SpellBuff.java b/src/main/java/electroblob/wizardry/spell/SpellBuff.java index 0c91c08f..f4277c69 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellBuff.java +++ b/src/main/java/electroblob/wizardry/spell/SpellBuff.java @@ -144,10 +144,10 @@ public class SpellBuff extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(r, g, b).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(r, g, b).spawn(world); } - Wizardry.proxy.spawnEntityParticle(world, caster, 15, r, g, b); + ParticleBuilder.create(Type.BUFF).entity(caster).clr(r, g, b).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/SpellConjuration.java b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java index 9dd9d068..c339932a 100644 --- a/src/main/java/electroblob/wizardry/spell/SpellConjuration.java +++ b/src/main/java/electroblob/wizardry/spell/SpellConjuration.java @@ -94,7 +94,7 @@ public class SpellConjuration extends Spell { double x = caster.posX + world.rand.nextDouble() * 2 - 1; double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double z = caster.posZ + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.7f, 0.9f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(0.7f, 0.9f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java index 1fee0dab..5166d9ba 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonIronGolem.java @@ -39,7 +39,7 @@ public class SummonIronGolem extends Spell { double x = pos.getX() + world.rand.nextDouble() * 2 - 1; double y = pos.getY() + 0.5 + world.rand.nextDouble(); double z = pos.getZ() + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).colour(0.6f, 0.6f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).clr(0.6f, 0.6f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java index e168d3b8..3be56349 100644 --- a/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java +++ b/src/main/java/electroblob/wizardry/spell/SummonSnowGolem.java @@ -39,7 +39,7 @@ public class SummonSnowGolem extends Spell { double x = pos.getX() + world.rand.nextDouble() * 2 - 1; double y = pos.getY() + 0.5 + world.rand.nextDouble(); double z = pos.getZ() + world.rand.nextDouble() * 2 - 1; - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).colour(0.6f, 0.6f, 1).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.1, 0).clr(0.6f, 0.6f, 1).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java index a96d65ea..06ca648b 100644 --- a/src/main/java/electroblob/wizardry/spell/Thunderstorm.java +++ b/src/main/java/electroblob/wizardry/spell/Thunderstorm.java @@ -5,12 +5,12 @@ import java.util.List; import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.Tier; -import electroblob.wizardry.entity.EntityArc; import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.ParticleBuilder; +import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.WizardryUtilities; import net.minecraft.entity.EntityLiving; @@ -72,12 +72,10 @@ public class Thunderstorm extends Spell { if(WizardryUtilities.isValidTarget(caster, secondaryTarget)){ - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(x, y + 1, z, secondaryTarget.posX, - secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ); - world.spawnEntity(arc); - }else{ + if(world.isRemote){ + + ParticleBuilder.create(Type.LIGHTNING).pos(x, y, z).target(secondaryTarget).spawn(world); + ParticleBuilder.spawnShockParticles(world, secondaryTarget.posX, secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2, secondaryTarget.posZ); @@ -102,14 +100,9 @@ public class Thunderstorm extends Spell { if(!secondaryTargets.contains(tertiaryTarget) && WizardryUtilities.isValidTarget(caster, tertiaryTarget)){ - if(!world.isRemote){ - EntityArc arc = new EntityArc(world); - arc.setEndpointCoords(secondaryTarget.posX, - secondaryTarget.posY + secondaryTarget.height / 2, secondaryTarget.posZ, - tertiaryTarget.posX, tertiaryTarget.posY + tertiaryTarget.height / 2, - tertiaryTarget.posZ); - world.spawnEntity(arc); - }else{ + if(world.isRemote){ + ParticleBuilder.create(Type.LIGHTNING).entity(secondaryTarget) + .pos(0, secondaryTarget.height/2, 0).target(tertiaryTarget).spawn(world); ParticleBuilder.spawnShockParticles(world, tertiaryTarget.posX, tertiaryTarget.getEntityBoundingBox().minY + tertiaryTarget.height / 2, tertiaryTarget.posZ); diff --git a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java index 37a55b55..1ab2670d 100644 --- a/src/main/java/electroblob/wizardry/spell/WallOfFrost.java +++ b/src/main/java/electroblob/wizardry/spell/WallOfFrost.java @@ -129,9 +129,9 @@ public class WallOfFrost extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ float brightness = world.rand.nextFloat(); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)) - .colour(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); - ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)) + .clr(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); + ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/spell/Wither.java b/src/main/java/electroblob/wizardry/spell/Wither.java index 3cacf432..54d260fb 100644 --- a/src/main/java/electroblob/wizardry/spell/Wither.java +++ b/src/main/java/electroblob/wizardry/spell/Wither.java @@ -64,8 +64,8 @@ public class Wither extends SpellRay { @Override protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ - ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).colour(0.1f, 0, 0).spawn(world); - ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)).colour(0.1f, 0, 0.05f).spawn(world); + ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0, 0).spawn(world); + ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0.1f, 0, 0.05f).spawn(world); } } diff --git a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java index 839dc831..eb78c50b 100644 --- a/src/main/java/electroblob/wizardry/util/ParticleBuilder.java +++ b/src/main/java/electroblob/wizardry/util/ParticleBuilder.java @@ -4,6 +4,7 @@ import java.util.Random; import electroblob.wizardry.Wizardry; import net.minecraft.entity.Entity; +import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -13,17 +14,14 @@ import net.minecraft.world.World; * "Don't waste time spawning particles manually - let {@code ParticleBuilder} do the work for you!" *

* Singleton class that builds wizardry particles. This is an alternative (and neater, I think) solution to using varargs. - * All building methods are chainable, so particles can be created using only one line of code (This is similar to the - * BufferBuilder system). The number of different combinations of parameters now required for the various particle + * All building methods are chainable, so particles can be created using only one line of code, similar to the + * {@code BufferBuilder} system. The number of different combinations of parameters now required for the various particle * types in wizardry made the method overloads in the proxies very cumbersome and inevitably resulted in redundant * parameters, which made the code messy and hard to read. Those methods have now been removed. *

- * It also goes without saying that this class should only ever be used client-side. Attempting to spawn particles - * on the server side will not work and will print a warning to the console. - *

* {@link ParticleBuilder#instance} retrieves the static instance of the particle builder. Use * {@link ParticleBuilder#particle(Type)} to start building a particle, or alternatively use the static - * convenience version {@link ParticleBuilder#create(Type)}. Use {@link ParticleBuilder#spawn()} + * convenience version {@link ParticleBuilder#create(Type)}. Use {@link ParticleBuilder#spawn(World)} * to finish building and spawn the particle. Between these two, a variety of parameters can be set using the various * setter methods (see individual method descriptions for more details). These, along with {@code ParticleBuilder.particle(...)}, * return the particle builder instance, allowing them to be chained together to spawn particles using a single line of code. @@ -32,10 +30,16 @@ import net.minecraft.world.World; *

* For example, a typical call to the particle builder might look something like this: *

- * ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).colour(r, g, b).spawn(world); + * ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).clr(r, g, b).spawn(world); + *

+ * It also goes without saying that this class should only ever be used client-side. Attempting to spawn particles + * on the server side will not work and will print a warning to the console. * @author Electroblob * @since Wizardry 4.2 */ +/* This isn't strictly a builder class in the traditional sense, because rather than returning the built object at the + * end, it sends it to be processed instead and returns nothing. It's also lazy, see the comment about builder variables + * below. */ public final class ParticleBuilder { /** The static instance of the particle builder. */ @@ -53,11 +57,16 @@ public final class ParticleBuilder { private float r, g, b; private float fr, fg, fb; private double radius; + private double rpt; private int lifetime; private boolean gravity; private boolean shaded; + private boolean collide; private float scale; private Entity entity; + private float yaw, pitch; + private double tx, ty, tz; + private Entity target; /** Enum constants representing the different types of particle added by wizardry. As of 4.2.0, this has been moved * from its own file {@code WizardryParticleType} to inside {@link ParticleBuilder}. This allowed its name to be @@ -67,33 +76,33 @@ public final class ParticleBuilder { *

* Individual constants have comments detailing their corresponding default parameters. A range of values indicates * randomness. */ - public static enum Type { - @Deprecated BLIZZARD, + public enum Type { + /** 3D-rendered light-beam particle.

Defaults:

Lifetime: 1 tick
Colour: white */ BEAM, + /** Helical animated 'buffing' particle.

Defaults:

Lifetime: 15 ticks + *
Velocity: (0, 0.27, 0)
Colour: white */ BUFF, /** Spiral particle, like potions.

Defaults:

Lifetime: 8-40 ticks
Colour: white */ DARK_MAGIC, /** Single pixel particle.

Defaults:

Lifetime: 16-80 ticks
Colour: white */ DUST, - /** Rapid flash, like fireworks.

Defaults:

Lifetime: 4 ticks
Colour: white */ FLASH, + /** Rapid flash, like fireworks.

Defaults:

Lifetime: 6 ticks
Colour: white */ FLASH, /** Small shard of ice.

Defaults:

Lifetime: 8-40 ticks
Gravity: true */ ICE, /** Single leaf.

Defaults:

Lifetime: 10-15 ticks
Velocity: (0, -0.03, 0) *
Colour: green/brown */ LEAF, + /** 3D-rendered lightning particle.

Defaults:

Lifetime: 3 ticks
Colour: blue */ LIGHTNING, + /** 2D lightning effect, normally on the ground.

Defaults:

Lifetime: 7 ticks + *
Facing: up */ LIGHTNING_PULSE, /** Bubble that doesn't burst in air.

Defaults:

Lifetime: 8-40 ticks */ MAGIC_BUBBLE, /** Scaleable, moving flame.

Defaults:

Lifetime: 8-40 ticks
*/ MAGIC_FIRE, /** Soft-edged round particle.

Defaults:

Lifetime: 8-40 ticks
Colour: white */ PATH, + /** Scorch mark.

Defaults:

Lifetime: 100-140 ticks
Colour: black
Fade: black */ SCORCH, /** Snowflake particle.

Defaults:

Lifetime: 40-50 ticks
Velocity: (0, -0.02, 0) */ SNOW, /** Animated lightning particle.

Defaults:

Lifetime: 3 ticks */ SPARK, - /** Animated sparkle particle.

Defaults:

Lifetime: 48-60 ticks
Colour: white */ SPARKLE, - @Deprecated SPARKLE_ROTATING + /** Animated sparkle particle.

Defaults:

Lifetime: 48-60 ticks
Colour: white */ SPARKLE } private ParticleBuilder(){ reset(); } - // Convenience methods - - // These may seem to go against the whole point of this class, but of course they return the ParticleBuilder instance - // so anything else can still be chained onto them - centralising commonly-used particle spawning patterns without - // losing any of the flexibility of the particle builder. In addition, callers of these methods are still free to - // change any of the parameters that were set within them afterwards. + // ============================================= Core builder methods ============================================= /** * Starts building a particle of the given type. Static convenience version of @@ -106,11 +115,406 @@ public final class ParticleBuilder { return ParticleBuilder.instance.particle(type); } + /** + * Starts building a particle of the given type. + * @param type The type of particle to build + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is already building. + */ + public ParticleBuilder particle(Type type){ + if(building) throw new IllegalStateException("Already Building! Particle being built: " + getCurrentParticleString()); + this.type = type; + this.building = true; + return this; + } + + /** Gets a readable string representation of the current builder parameters; used in error messages. */ + private String getCurrentParticleString(){ + return String.format("[ Type: %s, Position: (%s, %s, %s), Velocity: (%s, %s, %s), Colour: (%s, %s, %s), " + + "Fade Colour: (%s, %s, %s), Radius: %s, Revs/tick: %s, Lifetime: %s, Gravity: %s, Shaded: %s," + + "Scale: %s, Entity: %s ]", + type, x, y, z, vx, vy, vz, r, g, b, fr, fg, fb, radius, rpt, lifetime, gravity, shaded, scale, entity); + } + + /** + * Sets the position of the particle being built. If unspecified, this defaults to the origin (0, 0, 0). If an entity + * is specified using {@link ParticleBuilder#entity(Entity)}, this will be relative to that entity's position. + *

+ * Affects: All particle types + * @param x The x coordinate to set + * @param y The y coordinate to set + * @param z The z coordinate to set + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder pos(double x, double y, double z){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.x = x; + this.y = y; + this.z = z; + return this; + } + + /** + * Sets the position of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#pos( + * double, double, double)}, allowing for even more concise code when a vector is available. + *

+ * Affects: All particle types + * @param pos A vector representing the coordinates of the particle to be built. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder pos(Vec3d pos){ + return pos(pos.x, pos.y, pos.z); + } + + /** + * Sets the velocity of the particle being built. If unspecified, this defaults to the particle's default velocity, + * specified within its constructor. + *

+ * Affects: All particle types except {@link Type#DUST DUST} + * @param vx The x velocity to set + * @param vy The y velocity to set + * @param vz The z velocity to set + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder vel(double vx, double vy, double vz){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.vx = vx; + this.vy = vy; + this.vz = vz; + return this; + } + + /** + * Sets the velocity of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#vel( + * double, double, double)}, allowing for even more concise code when a vector is available. + *

+ * Affects: All particle types + * @param vel A vector representing the velocity of the particle to be built. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder vel(Vec3d vel){ + return vel(vel.x, vel.y, vel.z); + } + + /** + * Sets the colour of the particle being built. If unspecified, this defaults to the particle's default colour, + * specified within its constructor. + *

+ * Affects: {@link Type#DARK_MAGIC DARK_MAGIC}, {@link Type#DUST DUST}, {@link Type#FLASH FLASH}, + * {@link Type#LEAF LEAF}, {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE} + * @param r The red colour component to set; will be clamped to between 0 and 1 + * @param g The green colour component to set; will be clamped to between 0 and 1 + * @param b The blue colour component to set; will be clamped to between 0 and 1 + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder clr(float r, float g, float b){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.r = MathHelper.clamp(r, 0, 1); + this.g = MathHelper.clamp(g, 0, 1); + this.b = MathHelper.clamp(b, 0, 1); + return this; + } + + /** + * Sets the fade colour of the particle being built. If unspecified, this defaults to the whatever the particle's base + * colour is. + *

+ * Affects: {@link Type#DARK_MAGIC DARK_MAGIC}, {@link Type#DUST DUST}, {@link Type#FLASH FLASH}, + * {@link Type#LEAF LEAF}, {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE} + * @param r The red colour component to set; will be clamped to between 0 and 1 + * @param g The green colour component to set; will be clamped to between 0 and 1 + * @param b The blue colour component to set; will be clamped to between 0 and 1 + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder fade(float r, float g, float b){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.fr = MathHelper.clamp(r, 0, 1); + this.fg = MathHelper.clamp(g, 0, 1); + this.fb = MathHelper.clamp(b, 0, 1); + return this; + } + + /** + * Sets the scale of the particle being built. If unspecified, this defaults to 1. + *

+ * Affects: All particle types + * @param scale The scale to set, as a multiple of the particle's default scale + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder scale(float scale){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.scale = scale; + return this; + } + + /** + * Sets the lifetime of the particle being built. If unspecified, this defaults to the particle's default lifetime, + * specified within its constructor. + *

+ * Affects: All particle types + * @param lifetime The lifetime to set in ticks + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder time(int lifetime){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.lifetime = lifetime; + return this; + } + + /** + * Sets the spin parameters of the particle being built. If unspecified, these both default to 0. + *

+ * Affects: All particle types + * @param radius The rotation radius to set + * @param speed The rotation speed to set, in revolutions per tick + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder spin(double radius, double speed){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.radius = radius; + this.rpt = speed; + return this; + } + + /** + * Sets the gravity of the particle being built. If unspecified, this defaults to false. + *

+ * Affects: {@link Type#ICE ICE}, {@link Type#SPARKLE SPARKLE} + * @param gravity True to enable gravity for the particle, false to disable + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder gravity(boolean gravity){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.gravity = gravity; + return this; + } + + /** + * Sets the shading of the particle being built. If unspecified, this defaults to false. + *

+ * Affects: All particle types + * @param shaded True to enable shading for the particle, false for full brightness + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder shaded(boolean shaded){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.shaded = shaded; + return this; + } + + /** + * Sets the collisions of the particle being built. If unspecified, this defaults to false. + *

+ * Affects: All particle types + * @param collide True to enable block collisions for the particle, false to disable + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder collide(boolean collide){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.collide = collide; + return this; + } + + /** + * Sets the entity of the particle being built. This will cause the particle to move with the given entity, and will + * make the position specified using {@link ParticleBuilder#pos(double, double, double)} relative to that + * entity's position. + *

+ * Affects: All particle types + * @param entity The entity to set (passing in null will do nothing but will not cause any problems, so for the sake + * of conciseness it is not necessary to perform a null check on the passed-in argument) + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder entity(Entity entity){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.entity = entity; + return this; + } + + /** + * Sets the rotation of the particle being built. If unspecified, the particle will use the default behaviour and + * rotate to face the viewer. + *

+ * Affects: All particle types + * @param yaw The yaw angle to set in degrees, where 0 is south. + * @param pitch The pitch angle to set in degrees, where 0 is horizontal. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder face(float yaw, float pitch){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.yaw = yaw; + this.pitch = pitch; + return this; + } + + /** + * Sets the rotation of the particle being built. This is an {@code EnumFacing}-based alternative to {@link + * ParticleBuilder#face(float, float)} which sets the yaw and pitch to the appropriate angles for the given facing. + * For example, if the given facing is {@code NORTH}, the particle will render parallel to the north face of blocks. + *

+ * Affects: All particle types + * @param direction The {@code EnumFacing} direction to set. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder face(EnumFacing direction){ + return face(direction.getHorizontalAngle(), direction.getAxis().isVertical() ? direction.getAxisDirection().getOffset() * 90 : 0); + } + + /** + * Sets the target of the particle being built. This will cause the particle to stretch to touch the given position. + *

+ * Affects: + * @param x The target x-coordinate to set + * @param y The target y-coordinate to set + * @param z The target z-coordinate to set + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder target(double x, double y, double z){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.tx = x; + this.ty = y; + this.tz = z; + return this; + } + + /** + * Sets the target of the particle being built. This is a vector-based alternative to {@link ParticleBuilder# + * target(double, double, double)}, allowing for even more concise code when a vector is available. + *

+ * Affects: All particle types + * @param pos A vector representing the target position of the particle to be built. + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder target(Vec3d pos){ + return target(pos.x, pos.y, pos.z); + } + + /** + * Sets the target of the particle being built. This will cause the particle to stretch to touch the given entity. + *

+ * Affects: + * @param target The entity to set + * @return The particle builder instance, allowing other methods to be chained onto this one + * @throws IllegalStateException if the particle builder is not yet building. + */ + public ParticleBuilder target(Entity target){ + if(!building) throw new IllegalStateException("Not building yet!"); + this.target = target; + return this; + } + + /** + * Spawns the particle that has been built and resets the particle builder. + * @param world The world in which to spawn the particle + * @throws IllegalStateException if the particle builder is not yet building. + */ + public void spawn(World world){ + + if(!building) throw new IllegalStateException("Not building yet!"); + + if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity" + + "has been set correctly?"); + + if(!world.isRemote){ + Wizardry.logger.warn("ParticleBuilder.spawn(...) called on the server side! ParticleBuilder has prevented a " + + "server crash, but calling it on the server will do nothing. Consider adding a world.isRemote check."); + // Must stop here because the line after this if statement would crash the server! + reset(); + return; + } + + electroblob.wizardry.client.particle.ParticleWizardry particle = Wizardry.proxy.createParticle(type, world, x, y, z); + + if(particle == null){ + reset(); + return; + } + + // Anything with an if statement here allows default values to be set in particle constructors + particle.multipleParticleScaleBy(scale); + if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz); + if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b); + if(fr >= 0 && fg >= 0 && fb >= 0)particle.setFadeColour(fr, fg, fb); + if(lifetime >= 0) particle.setMaxAge(lifetime); + particle.setGravity(gravity); + particle.setShaded(shaded); + particle.setCollisions(collide); + if(radius > 0) particle.setSpin(radius, rpt); + particle.setEntity(entity); + if(!Float.isNaN(yaw) && !Float.isNaN(pitch)) particle.setFacing(yaw, pitch); + particle.setTargetPosition(tx, ty, tz); + particle.setTargetEntity(target); + + net.minecraft.client.Minecraft.getMinecraft().effectRenderer.addEffect(particle); + + reset(); + } + + /** Resets the state of the particle builder and resets all the builder variables to their default values. */ + private void reset(){ + building = false; + type = null; + x = 0; + y = 0; + z = 0; + // NaN indicates the velocity was not set (can't use -1 since it could very reasonably be -1) + // For all other values -1 indicates the value was not set + vx = Double.NaN; + vy = Double.NaN; + vz = Double.NaN; + r = -1; + g = -1; + b = -1; + fr = -1; + fg = -1; + fb = -1; + radius = 0; + rpt = 0; + lifetime = -1; + gravity = false; + shaded = false; + collide = false; + scale = 1; + entity = null; + yaw = Float.NaN; + pitch = Float.NaN; + tx = Double.NaN; + ty = Double.NaN; + tz = Double.NaN; + target = null; + } + + // ============================================== Convenience methods ============================================== + + // These may seem to go against the whole point of this class, but of course they return the ParticleBuilder instance + // so anything else can still be chained onto them - centralising commonly-used particle spawning patterns without + // losing any of the flexibility of the particle builder. In addition, callers of these methods are still free to + // change any of the parameters that were set within them afterwards. + /** * Starts building a particle of the given type and positions it randomly within the given entity's bounding box. * Equivalent to calling {@code ParticleBuilder.create(type).pos(...)}; users should chain any additional builder * methods onto this one and finish with {@code .spawn(world)} as normal. * Used extensively with summoned creatures; makes code much neater and more concise. + *

+ * N.B. this does not cause the particle to move with the given entity. * @param type The type of particle to build * @param entity The entity to position the particle at * @return The particle builder instance, allowing other methods to be chained onto this one @@ -152,276 +556,6 @@ public final class ParticleBuilder { return ParticleBuilder.instance.particle(type).pos(px, py, pz); } - // Core builder methods - - /** - * Starts building a particle of the given type. - * @param type The type of particle to build - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is already building. - */ - public ParticleBuilder particle(Type type){ - if(building) throw new IllegalStateException("Already building!"); - this.type = type; - this.building = true; - return this; - } - - /** - * Sets the position of the particle being built. If unspecified, this defaults to the origin (0, 0, 0). - *

- * Affects: All particle types - * @param x The x coordinate to set - * @param y The y coordinate to set - * @param z The z coordinate to set - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder pos(double x, double y, double z){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.x = x; - this.y = y; - this.z = z; - return this; - } - - /** - * Sets the position of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#pos( - * double, double, double)}, allowing for even more concise code when a vector is available. - *

- * Affects: All particle types - * @param pos A vector representing the coordinates of the particle to be built. - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder pos(Vec3d pos){ - return pos(pos.x, pos.y, pos.z); - } - - /** - * Sets the velocity of the particle being built. If unspecified, this defaults to the particle's default velocity, - * specified within its constructor. - *

- * Affects: All particle types except {@link Type#DUST DUST} - * @param x The x coordinate to set - * @param y The y coordinate to set - * @param z The z coordinate to set - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder vel(double vx, double vy, double vz){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.vx = vx; - this.vy = vy; - this.vz = vz; - return this; - } - - /** - * Sets the velocity of the particle being built. This is a vector-based alternative to {@link ParticleBuilder#vel( - * double, double, double)}, allowing for even more concise code when a vector is available. - *

- * Affects: All particle types - * @param vel A vector representing the velocity of the particle to be built. - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder vel(Vec3d vel){ - return vel(vel.x, vel.y, vel.z); - } - - /** - * Sets the colour of the particle being built. If unspecified, this defaults to the particle's default colour, - * specified within its constructor. - *

- * Affects: {@link Type#DARK_MAGIC DARK_MAGIC}, {@link Type#DUST DUST}, {@link Type#FLASH FLASH}, - * {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE} - * @param r The red colour component to set; will be clamped to between 0 and 1 - * @param g The green colour component to set; will be clamped to between 0 and 1 - * @param b The blue colour component to set; will be clamped to between 0 and 1 - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder colour(float r, float g, float b){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.r = MathHelper.clamp(r, 0, 1); - this.g = MathHelper.clamp(g, 0, 1); - this.b = MathHelper.clamp(b, 0, 1); - return this; - } - - /** - * Sets the fade colour of the particle being built. If unspecified, this defaults to the whatever the particle's base - * colour is. - *

- * Affects: {@link Type#DUST DUST}, {@link Type#PATH PATH}, {@link Type#SPARKLE SPARKLE} - * @param r The red colour component to set; will be clamped to between 0 and 1 - * @param g The green colour component to set; will be clamped to between 0 and 1 - * @param b The blue colour component to set; will be clamped to between 0 and 1 - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder fade(float r, float g, float b){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.fr = MathHelper.clamp(r, 0, 1); - this.fg = MathHelper.clamp(g, 0, 1); - this.fb = MathHelper.clamp(b, 0, 1); - return this; - } - - /** - * Sets the scale of the particle being built. If unspecified, this defaults to 1. - *

- * Affects: All particle types - * @param scale The scale to set, as a multiple of the particle's default scale - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder scale(float scale){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.scale = scale; - return this; - } - - /** - * Sets the lifetime of the particle being built. If unspecified, this defaults to the particle's default lifetime, - * specified within its constructor. - *

- * Affects: All particle types - * @param lifetime The lifetime to set in ticks - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder lifetime(int lifetime){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.lifetime = lifetime; - return this; - } - - /** - * Sets the rotation radius of the particle being built. If unspecified, this defaults to 0. - *

- * Affects: All particle types - * @param radius The rotation radius to set - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder radius(double radius){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.radius = radius; - return this; - } - - /** - * Sets the gravity of the particle being built. If unspecified, this defaults to false. - *

- * Affects: {@link Type#ICE ICE}, {@link Type#SPARKLE SPARKLE} - * @param gravity True to enable gravity for the particle, false to disable - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder gravity(boolean gravity){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.gravity = gravity; - return this; - } - - /** - * Sets the shading of the particle being built. If unspecified, this defaults to false. - *

- * Affects: All particle types - * @param shaded True to enable shading for the particle, false for full brightness - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder shaded(boolean shaded){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.shaded = shaded; - return this; - } - - /** - * Sets the entity of the particle being built. This must be specified for entity-linked particles. - * @param entity The entity to set - * @return The particle builder instance, allowing other methods to be chained onto this one - * @throws IllegalStateException if the particle builder is not yet building. - */ - public ParticleBuilder entity(Entity entity){ - if(!building) throw new IllegalStateException("Not building yet!"); - this.entity = entity; - return this; - } - - /** - * Spawns the particle that has been built and resets the particle builder. - * @param world The world in which to spawn the particle - * @throws IllegalStateException if the particle builder is not yet building. - */ - public void spawn(World world){ - - if(!building) throw new IllegalStateException("Not building yet!"); - - if(y < 0 && entity == null) Wizardry.logger.warn("Spawning particle below y = 0 - are you sure the position/entity" - + "has been set correctly?"); - - if(!world.isRemote){ - Wizardry.logger.warn("ParticleBuilder.spawn(...) called on the server side! ParticleBuilder has prevented a" - + "server crash, but calling it on the server will do nothing. Consider adding a world.isRemote check."); - // Must stop here because the line after this if statement would crash the server! - reset(); - return; - } - - electroblob.wizardry.client.particle.ParticleWizardry particle = Wizardry.proxy.createParticle(type, world, x, y, z); - - if(particle == null){ - reset(); - return; - } - - particle.multipleParticleScaleBy(scale); - if(!Double.isNaN(vx) && !Double.isNaN(vy) && !Double.isNaN(vz)) particle.setVelocity(vx, vy, vz); - if(r >= 0 && g >= 0 && b >= 0) particle.setRBGColorF(r, g, b); - if(fr >= 0 && fg >= 0 && fb >= 0){ - particle.setFadeColour(fr, fg, fb); - }else{ - particle.setFadeColour(r, g, b); // If fade colour was unspecified, it defaults to the main colour - } - if(lifetime >= 0) particle.setLifetime(lifetime); - particle.setGravity(gravity); - particle.setShaded(shaded); - - net.minecraft.client.Minecraft.getMinecraft().effectRenderer.addEffect(particle); - - reset(); - } - - /** Resets the state of the particle builder and resets all the builder variables to their default values. */ - private void reset(){ - building = false; - type = null; - x = 0; - y = 0; - z = 0; - // NaN indicates the velocity was not set (can't use -1 since it could very reasonably be -1) - // For all other values -1 indicates the value was not set - vx = Double.NaN; - vy = Double.NaN; - vz = Double.NaN; - r = -1; - g = -1; - b = -1; - fr = -1; - fg = -1; - fb = -1; - radius = 0; - lifetime = -1; - gravity = false; - shaded = false; - scale = 1; - entity = null; - } - // Methods for spawning specific effects (similar to the FX playing methods with the ids in RenderGlobal) /** Spawns spark and large smoke particles (8 of each) within a 1x1x1 volume centred on the given position. */ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_0.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_0.png new file mode 100644 index 00000000..531b56b5 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_1.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_1.png new file mode 100644 index 00000000..285df2cc Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_2.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_2.png new file mode 100644 index 00000000..44c63a7b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_3.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_3.png new file mode 100644 index 00000000..b12745e9 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_4.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_4.png new file mode 100644 index 00000000..389abbd7 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_4.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_5.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_5.png new file mode 100644 index 00000000..e1bdc75d Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_5.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_6.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_6.png new file mode 100644 index 00000000..c597f415 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_6.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_7.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_7.png new file mode 100644 index 00000000..b09a66b4 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/ice_7.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/ice_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/ice_particles.png deleted file mode 100644 index 96c99ead..00000000 Binary files a/src/main/resources/assets/ebwizardry/textures/particle/ice_particles.png and /dev/null differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png new file mode 100644 index 00000000..6c1dabf2 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png new file mode 100644 index 00000000..990fba4b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_10.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_10.png new file mode 100644 index 00000000..bdc4dc43 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_10.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_11.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_11.png new file mode 100644 index 00000000..9a6e4d9c Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_11.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_12.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_12.png new file mode 100644 index 00000000..abc96674 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_12.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png new file mode 100644 index 00000000..85124935 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_13.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png new file mode 100644 index 00000000..50a9fc70 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_14.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_15.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_15.png new file mode 100644 index 00000000..8eea8be9 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_15.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_2.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_2.png new file mode 100644 index 00000000..f9804dc0 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_3.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_3.png new file mode 100644 index 00000000..d2a7c3c6 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_4.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_4.png new file mode 100644 index 00000000..7b39ed23 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_4.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_5.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_5.png new file mode 100644 index 00000000..1aa1c430 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_5.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_6.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_6.png new file mode 100644 index 00000000..834799fc Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_6.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png new file mode 100644 index 00000000..e0a4a796 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_7.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_8.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_8.png new file mode 100644 index 00000000..399d3a9a Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_8.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png new file mode 100644 index 00000000..29c3868d Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/leaf_9.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/leaf_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/leaf_particles.png deleted file mode 100644 index 627b30ef..00000000 Binary files a/src/main/resources/assets/ebwizardry/textures/particle/leaf_particles.png and /dev/null differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_0.png new file mode 100644 index 00000000..e8961570 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_1.png new file mode 100644 index 00000000..d27a4235 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_2.png new file mode 100644 index 00000000..ac92d34b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_3.png new file mode 100644 index 00000000..b78a86ff Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_0_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_0.png new file mode 100644 index 00000000..60d2e3d2 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_1.png new file mode 100644 index 00000000..0d98efd6 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_2.png new file mode 100644 index 00000000..19d23ff3 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_3.png new file mode 100644 index 00000000..ab8dbf03 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_1_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_0.png new file mode 100644 index 00000000..4b189159 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_1.png new file mode 100644 index 00000000..224c39a8 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_2.png new file mode 100644 index 00000000..bc914ecc Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_3.png new file mode 100644 index 00000000..b2d2c942 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_2_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_0.png new file mode 100644 index 00000000..3b33edd7 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_1.png new file mode 100644 index 00000000..bd62e1ca Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_2.png new file mode 100644 index 00000000..e5c306fa Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_3.png new file mode 100644 index 00000000..ee15f872 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_3_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_0.png new file mode 100644 index 00000000..b5d0830b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_1.png new file mode 100644 index 00000000..96304d15 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_2.png new file mode 100644 index 00000000..36a82906 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_3.png new file mode 100644 index 00000000..a185c530 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_4_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_0.png new file mode 100644 index 00000000..3b9dd28b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_1.png new file mode 100644 index 00000000..6607b21f Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_2.png new file mode 100644 index 00000000..706d10a1 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_3.png new file mode 100644 index 00000000..4a67952b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_5_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_0.png new file mode 100644 index 00000000..07ac3f77 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_1.png new file mode 100644 index 00000000..c7a7d874 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_2.png new file mode 100644 index 00000000..3dddd174 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_3.png new file mode 100644 index 00000000..e84fbc4d Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_6_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_0.png new file mode 100644 index 00000000..7bc98d4e Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_1.png new file mode 100644 index 00000000..5ec85410 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_2.png new file mode 100644 index 00000000..249ea1fc Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_3.png new file mode 100644 index 00000000..a7e8abb6 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/lightning_7_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/lightning_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_particles.png deleted file mode 100644 index 94dc49c5..00000000 Binary files a/src/main/resources/assets/ebwizardry/textures/particle/lightning_particles.png and /dev/null differ diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_0.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_0.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_0.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_0.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_1.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_1.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_1.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_1.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_2.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_2.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_2.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_2.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_3.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_3.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_3.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_3.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_4.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_4.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_4.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_4.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_5.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_5.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_5.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_5.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_6.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_6.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_6.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_6.png diff --git a/src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_7.png b/src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_7.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/entity/lightning_pulse_7.png rename to src/main/resources/assets/ebwizardry/textures/particle/lightning_pulse_7.png diff --git a/src/main/resources/assets/ebwizardry/textures/particle/path_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/path.png similarity index 100% rename from src/main/resources/assets/ebwizardry/textures/particle/path_particles.png rename to src/main/resources/assets/ebwizardry/textures/particle/path.png diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_0.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_0.png new file mode 100644 index 00000000..b2d2a22d Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_1.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_1.png new file mode 100644 index 00000000..7eba17d2 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_2.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_2.png new file mode 100644 index 00000000..8a908c43 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_3.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_3.png new file mode 100644 index 00000000..7f09067a Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_4.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_4.png new file mode 100644 index 00000000..65765f7b Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_4.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_5.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_5.png new file mode 100644 index 00000000..904c7093 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_5.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_6.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_6.png new file mode 100644 index 00000000..454b064c Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_6.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/scorch_7.png b/src/main/resources/assets/ebwizardry/textures/particle/scorch_7.png new file mode 100644 index 00000000..547fc6ef Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/scorch_7.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_0.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_0.png new file mode 100644 index 00000000..53ed7b63 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/snow_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_1.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_1.png new file mode 100644 index 00000000..6d792d6d Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/snow_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_2.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_2.png new file mode 100644 index 00000000..6e8d60a1 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/snow_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_3.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_3.png new file mode 100644 index 00000000..3f6a9c91 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/snow_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/snow_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/snow_particles.png deleted file mode 100644 index 9d636de1..00000000 Binary files a/src/main/resources/assets/ebwizardry/textures/particle/snow_particles.png and /dev/null differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_0.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_0.png new file mode 100644 index 00000000..be4ee4f1 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_0.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_1.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_1.png new file mode 100644 index 00000000..5264ba88 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_1.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_10.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_10.png new file mode 100644 index 00000000..74f32788 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_10.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_2.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_2.png new file mode 100644 index 00000000..8db620f5 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_2.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png new file mode 100644 index 00000000..dcad4910 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_3.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_4.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_4.png new file mode 100644 index 00000000..9f2104b4 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_4.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_5.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_5.png new file mode 100644 index 00000000..9783e657 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_5.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png new file mode 100644 index 00000000..985abad9 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_6.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_7.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_7.png new file mode 100644 index 00000000..041dccff Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_7.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_8.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_8.png new file mode 100644 index 00000000..4da926fe Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_8.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_9.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_9.png new file mode 100644 index 00000000..f11b9688 Binary files /dev/null and b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_9.png differ diff --git a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_particles.png b/src/main/resources/assets/ebwizardry/textures/particle/sparkle_particles.png deleted file mode 100644 index d767eac3..00000000 Binary files a/src/main/resources/assets/ebwizardry/textures/particle/sparkle_particles.png and /dev/null differ