The great particle refactoring part 2: Splitting and Streamlining!

- Splits all particle textures into individual files intead of sprite sheets
- Replaces arc and lightning pulse entities with particles
- Pulls particle code up to the general ParticleWizardry so behaviours such as spin can be applied to all particle types
- Renames a few ParticleBuilder methods for conciseness.
- Adds a few new particle effects to various spells and entities, with a slight tweak to EntityMagicArrow#onBlockHit to facilitate impact effects
This commit is contained in:
Electroblob77
2019-01-01 21:40:04 +00:00
parent ad363c64af
commit b374f71533
201 changed files with 1682 additions and 1551 deletions
@@ -70,8 +70,6 @@ public class CommonProxy {
public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius,
int maxAge, IBlockState block, BlockPos pos){ int maxAge, IBlockState block, BlockPos pos){
} }
public void spawnEntityParticle(World world, Entity entity, int maxAge, float r, float g, float b){}
// SECTION Items // SECTION Items
// =============================================================================================================== // ===============================================================================================================
@@ -206,22 +206,13 @@ public final class WizardryEventHandler {
// Static Aura // Static Aura
if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura)){ if(event.getEntityLiving().isPotionActive(WizardryPotions.static_aura)){
if(!world.isRemote){ if(world.isRemote){
EntityArc arc = new EntityArc(world);
arc.setEndpointCoords(event.getEntityLiving().posX, event.getEntityLiving().posY + 1, ParticleBuilder.create(Type.LIGHTNING).entity(event.getEntity()).pos(0, event.getEntity().height/2, 0)
event.getEntityLiving().posZ, attacker.posX, attacker.posY + attacker.height / 2, .target(attacker).spawn(world);
attacker.posZ);
world.spawnEntity(arc); ParticleBuilder.spawnShockParticles(world, attacker.posX,
}else{ attacker.getEntityBoundingBox().minY + attacker.height, attacker.posZ);
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);
}
} }
attacker.attackEntityFrom( attacker.attackEntityFrom(
@@ -43,7 +43,7 @@ public class BlockCrystalFlower extends BlockBush {
if(world.isRemote && random.nextBoolean()){ if(world.isRemote && random.nextBoolean()){
ParticleBuilder.create(Type.SPARKLE) 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) .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); 0.5f + (random.nextFloat() / 2)).spawn(world);
} }
} }
@@ -70,9 +70,9 @@ public class BlockSpectral extends BlockContainer {
// Top surface // Top surface
for(int i=0; i<2; i++){ for(int i=0; i<2; i++){
ParticleBuilder.create(Type.DUST) ParticleBuilder.create(Type.DUST)
.pos(pos.getX() + random.nextDouble(), pos.getY() + 1, pos.getZ() + random.nextDouble()) .pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble())
.lifetime((int)(16.0D / (Math.random() * 0.8D + 0.2D))) .time((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) .clr(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f)
.shaded(true).spawn(world); .shaded(true).spawn(world);
} }
} }
@@ -13,25 +13,9 @@ import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.gui.GuiSpellDisplay; import electroblob.wizardry.client.gui.GuiSpellDisplay;
import electroblob.wizardry.client.gui.GuiWizardHandbook; import electroblob.wizardry.client.gui.GuiWizardHandbook;
import electroblob.wizardry.client.model.ModelWizardArmour; import electroblob.wizardry.client.model.ModelWizardArmour;
import electroblob.wizardry.client.particle.ParticleBlizzard; import electroblob.wizardry.client.particle.*;
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.ParticleWizardry.IWizardryParticleFactory; import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory;
import electroblob.wizardry.client.renderer.LayerStone; import electroblob.wizardry.client.renderer.LayerStone;
import electroblob.wizardry.client.renderer.RenderArc;
import electroblob.wizardry.client.renderer.RenderArcaneWorkbench; import electroblob.wizardry.client.renderer.RenderArcaneWorkbench;
import electroblob.wizardry.client.renderer.RenderBlackHole; import electroblob.wizardry.client.renderer.RenderBlackHole;
import electroblob.wizardry.client.renderer.RenderBlank; 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.RenderIceGiant;
import electroblob.wizardry.client.renderer.RenderIceSpike; import electroblob.wizardry.client.renderer.RenderIceSpike;
import electroblob.wizardry.client.renderer.RenderLightningDisc; import electroblob.wizardry.client.renderer.RenderLightningDisc;
import electroblob.wizardry.client.renderer.RenderLightningPulse;
import electroblob.wizardry.client.renderer.RenderMagicArrow; import electroblob.wizardry.client.renderer.RenderMagicArrow;
import electroblob.wizardry.client.renderer.RenderMagicLight; import electroblob.wizardry.client.renderer.RenderMagicLight;
import electroblob.wizardry.client.renderer.RenderPhoenix; 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.RenderSpiritWolf;
import electroblob.wizardry.client.renderer.RenderStatue; import electroblob.wizardry.client.renderer.RenderStatue;
import electroblob.wizardry.client.renderer.RenderWizard; import electroblob.wizardry.client.renderer.RenderWizard;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.entity.EntityShield; import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.construct.EntityArrowRain; import electroblob.wizardry.entity.construct.EntityArrowRain;
import electroblob.wizardry.entity.construct.EntityBlackHole; 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.EntityHammer;
import electroblob.wizardry.entity.construct.EntityHealAura; import electroblob.wizardry.entity.construct.EntityHealAura;
import electroblob.wizardry.entity.construct.EntityIceSpike; import electroblob.wizardry.entity.construct.EntityIceSpike;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import electroblob.wizardry.entity.construct.EntityLightningSigil; import electroblob.wizardry.entity.construct.EntityLightningSigil;
import electroblob.wizardry.entity.construct.EntityTornado; import electroblob.wizardry.entity.construct.EntityTornado;
import electroblob.wizardry.entity.living.EntityDecoy; import electroblob.wizardry.entity.living.EntityDecoy;
@@ -291,27 +272,30 @@ public class ClientProxy extends CommonProxy {
public void initParticleFactories(){ public void initParticleFactories(){
factories = new HashMap<>(); factories = new HashMap<>();
factories.put(Type.BLIZZARD, (world, x, y, z) -> new ParticleBlizzard(world, x, y, z)); factories.put(Type.BEAM, ParticleBeam::new);
factories.put(Type.DARK_MAGIC, (world, x, y, z) -> new ParticleDarkMagic(world, x, y, z)); factories.put(Type.BUFF, ParticleBuff::new);
factories.put(Type.DUST, (world, x, y, z) -> new ParticleDust(world, x, y, z)); factories.put(Type.DARK_MAGIC, ParticleDarkMagic::new);
factories.put(Type.FLASH, (world, x, y, z) -> new ParticleFlash(world, x, y, z)); factories.put(Type.DUST, ParticleDust::new);
factories.put(Type.ICE, (world, x, y, z) -> new ParticleIce(world, x, y, z)); factories.put(Type.FLASH, ParticleFlash::new);
factories.put(Type.LEAF, (world, x, y, z) -> new ParticleLeaf(world, x, y, z)); factories.put(Type.ICE, ParticleIce::new);
factories.put(Type.MAGIC_BUBBLE, (world, x, y, z) -> new ParticleMagicBubble(world, x, y, z)); factories.put(Type.LEAF, ParticleLeaf::new);
factories.put(Type.MAGIC_FIRE, (world, x, y, z) -> new ParticleMagicFlame(world, x, y, z)); factories.put(Type.LIGHTNING, ParticleLightning::new);
factories.put(Type.PATH, (world, x, y, z) -> new ParticlePath(world, x, y, z)); factories.put(Type.LIGHTNING_PULSE, ParticleLightningPulse::new);
factories.put(Type.SNOW, (world, x, y, z) -> new ParticleSnow(world, x, y, z)); factories.put(Type.MAGIC_BUBBLE, ParticleMagicBubble::new);
factories.put(Type.SPARK, (world, x, y, z) -> new ParticleSpark(world, x, y, z)); factories.put(Type.MAGIC_FIRE, ParticleMagicFlame::new);
factories.put(Type.SPARKLE, (world, x, y, z) -> new ParticleSparkle(world, x, y, z)); factories.put(Type.PATH, ParticlePath::new);
factories.put(Type.SPARKLE_ROTATING, (world, x, y, z) -> new ParticleRotatingSparkle(world, x, y, z)); 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 @Override
public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){ public ParticleWizardry createParticle(Type type, World world, double x, double y, double z){
IWizardryParticleFactory factory = factories.get(type); IWizardryParticleFactory factory = factories.get(type);
if(factory == null){ 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 null;
} }
return factory.createParticle(world, x, y, z); 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 x = caster.posX + radius * Math.cos(angle);
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2; double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble() * 2;
double z = caster.posZ + radius * Math.sin(angle); 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) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.02, 0).clr(0.6f, 1, 0.6f)
.lifetime(80 + world.rand.nextInt(10)).spawn(world); .time(80 + world.rand.nextInt(10)).spawn(world);
} }
for(int i = 0; i < 20; i++){ for(int i = 0; i < 20; i++){
double radius = 1; 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)); manager -> new RenderProjectile(manager, 0.6f, new ResourceLocation(Wizardry.MODID, "textures/items/smoke_bomb.png"), false));
// Effects and constructs // Effects and constructs
RenderingRegistry.registerEntityRenderingHandler(EntityArc.class, RenderArc::new);
RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new); RenderingRegistry.registerEntityRenderingHandler(EntityBlackHole.class, RenderBlackHole::new);
RenderingRegistry.registerEntityRenderingHandler(EntityShield.class, RenderBlank::new); RenderingRegistry.registerEntityRenderingHandler(EntityShield.class, RenderBlank::new);
RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new); RenderingRegistry.registerEntityRenderingHandler(EntityBubble.class, RenderBubble::new);
@@ -608,7 +591,6 @@ public class ClientProxy extends CommonProxy {
RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class, RenderingRegistry.registerEntityRenderingHandler(EntityFireRing.class,
manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f)); manager -> new RenderFireRing(manager, new ResourceLocation(Wizardry.MODID, "textures/entity/ring_of_fire.png"), 5.0f));
RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new); RenderingRegistry.registerEntityRenderingHandler(EntityDecay.class, RenderDecay::new);
RenderingRegistry.registerEntityRenderingHandler(EntityLightningPulse.class, manager -> new RenderLightningPulse(manager, 8.0f));
// TESRs // TESRs
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench()); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench());
@@ -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();
}
}
@@ -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);
}
}
}
@@ -21,36 +21,41 @@ import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT) @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 static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/buff.png");
private final boolean mirror; private final boolean mirror;
public ParticleBuff(World world, Entity entity, float r, float g, float b, boolean mirror){ public ParticleBuff(World world, double x, double y, double z){
super(world, entity); super(world, x, y, z);
this.setRBGColorF(r, g, b); this.setVelocity(0, 0.27, 0); // Approximately what it was before
this.mirror = mirror; this.mirror = world.rand.nextBoolean();
} this.setMaxAge(15);
this.setGravity(false);
public ParticleBuff(World world, Entity entity, int maxAge, float r, float g, float b, boolean mirror){ this.canCollide = false;
super(world, entity, maxAge);
this.setRBGColorF(r, g, b);
this.mirror = mirror;
}
@Override
public void init(){
this.particleGravity = 0;
this.posY += 1;
} }
@Override @Override
public void onUpdate(){ public void onUpdate(){
super.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; 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 @Override
public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ, public void renderParticle(BufferBuilder buffer, Entity viewer, float partialTicks, float rotationX, float rotationZ,
float rotationYZ, float rotationXY, float rotationXZ){ float rotationYZ, float rotationXY, float rotationXZ){
@@ -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. <b>State changes should be done
* using GLStateManager, not using GL11 directly</b> (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. <b>State changes should be done
* using GLStateManager, not using GL11 directly</b> (as is the case with all rendering code now).
*/
public void undoGLStateChanges(){
}
}
@@ -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);
}
}
@@ -17,13 +17,13 @@ public class ParticleFlash extends ParticleWizardry {
super(world, x, y, z); super(world, x, y, z);
this.setRBGColorF(1, 1, 1); this.setRBGColorF(1, 1, 1);
this.particleScale = 0.6f; // 7.1f is the value used in fireworks this.particleScale = 0.6f; // 7.1f is the value used in fireworks
this.particleMaxAge = 4; this.particleMaxAge = 6;
} }
@Override @Override
public void renderParticle(BufferBuilder buffer, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ){ 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); 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) * 0.25F * 0.5F); 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 f5 = (float)(this.prevPosX + (this.posX - this.prevPosX) * (double)partialTicks - interpPosX);
float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY); float f6 = (float)(this.prevPosY + (this.posY - this.prevPosY) * (double)partialTicks - interpPosY);
float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ); float f7 = (float)(this.prevPosZ + (this.posZ - this.prevPosZ) * (double)partialTicks - interpPosZ);
@@ -1,40 +1,36 @@
package electroblob.wizardry.client.particle; package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; 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.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
public class ParticleIce extends ParticleCustomTexture { @Mod.EventBusSubscriber(Side.CLIENT)
public class ParticleIce extends ParticleWizardry {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/particle/ice_particles.png");
private static final ResourceLocation[] TEXTURES = generateTextures("ice", 8);
public ParticleIce(World world, double x, double y, double z){ 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; this.canCollide = true;
// Defaults // Defaults
this.setRBGColorF(1, 1, 1);
this.particleScale *= 0.75f; this.particleScale *= 0.75f;
this.setGravity(true); this.setGravity(true);
this.shaded = false; this.shaded = false;
} }
@Override @SubscribeEvent
public ResourceLocation getTexture(){ public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
return TEXTURE; for(ResourceLocation texture : TEXTURES){
} event.getMap().registerSprite(texture);
}
@Override
protected int getXFrames(){
return 4;
}
@Override
protected int getYFrames(){
return 4;
} }
} }
@@ -1,41 +1,47 @@
package electroblob.wizardry.client.particle; package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; 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.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT) @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, private static final ResourceLocation[] TEXTURES = generateTextures("leaf", 16);
"textures/particle/leaf_particles.png");
public ParticleLeaf(World world, double x, double y, double z){ 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.setVelocity(0, -0.03, 0);
this.setLifetime(10 + rand.nextInt(5)); this.setMaxAge(10 + rand.nextInt(5));
this.setParticleTextureIndex(rand.nextInt(16));
this.particleScale *= 1.4f; this.particleScale *= 1.4f;
this.particleGravity = 0; this.particleGravity = 0;
this.canCollide = true; this.canCollide = true;
// Produces a variety of browns and greens // 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); this.setRBGColorF(0.1f + 0.3f * world.rand.nextFloat(), 0.5f + 0.3f * world.rand.nextFloat(), 0.1f);
} }
@Override @Override
public ResourceLocation getTexture(){ public void onUpdate(){
return TEXTURE;
super.onUpdate();
// Fading
if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
}
} }
@Override @SubscribeEvent
protected int getXFrames(){ public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
return 4; for(ResourceLocation texture : TEXTURES){
} event.getMap().registerSprite(texture);
}
@Override
protected int getYFrames(){
return 4;
} }
} }
@@ -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<numberOfSegments-1; i++){
double px2 = (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale;
double py2 = (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale;
double pz2 = pz + length/(double)numberOfSegments; // For now they are all the same length
drawSegment(tessellator, layer, px, py, pz, px2, py2, pz2, THICKNESS*particleScale);
// Forks
if(random.nextFloat() < FORK_CHANCE){
double px3=px, py3=py, pz3=pz;
for(int j=0; j<random.nextInt(MAX_FORK_SEGMENTS-1)+1; j++){
// Forks set their centreline to the x/y coordinates of the vertex they originate from
double px4 = px3 + (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale;
double py4 = py3 + (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale;
double pz4 = pz3 + MIN_SEGMENT_LENGTH + random.nextDouble()*(MAX_SEGMENT_LENGTH - MIN_SEGMENT_LENGTH);
drawSegment(tessellator, layer, px3, py3, pz3, px4, py4, pz4, THICKNESS*0.8f*particleScale);
// Forks of forks
if(random.nextFloat() < FORK_CHANCE){
double px5 = px3 + (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale;
double py5 = py3 + (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale;
double pz5 = pz3 + MIN_SEGMENT_LENGTH + random.nextDouble()*(MAX_SEGMENT_LENGTH - MIN_SEGMENT_LENGTH);
drawSegment(tessellator, layer, px3, py3, pz3, px5, py5, pz5, THICKNESS*0.6f*particleScale);
}
px3 = px4;
py3 = py4;
pz3 = pz4;
}
}
px = px2;
py = py2;
pz = pz2;
}
// Last segment has a specific end position and cannot fork.
double px2 = freeEnd ? (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale : 0;
double py2 = freeEnd ? (random.nextDouble()*2-1)*VERTEX_JITTER*particleScale : 0;
drawSegment(tessellator, layer, px, py, pz, px2, py2, length, THICKNESS*particleScale);
}
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();
}
}
@@ -0,0 +1,38 @@
package electroblob.wizardry.client.particle;
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)
@Mod.EventBusSubscriber(Side.CLIENT)
public class ParticleLightningPulse extends ParticleWizardry {
private static final ResourceLocation[] TEXTURES = generateTextures("lightning_pulse", 8);
public ParticleLightningPulse(World world, double x, double y, double z){
super(world, x, y, z, TEXTURES);
this.particleScale = 32f;
this.setRBGColorF(1, 1, 1);
this.shaded = false;
this.canCollide = false;
this.setMaxAge(7); // Lifetime defaults to 7 (and is very unlikely to be changed)
// Faces up by default
this.pitch = 90;
this.yaw = 0;
}
@SubscribeEvent
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
for(ResourceLocation texture : TEXTURES){
event.getMap().registerSprite(texture);
}
}
}
@@ -9,9 +9,7 @@ public class ParticleMagicBubble extends ParticleWizardry {
public ParticleMagicBubble(World world, double x, double y, double z){ public ParticleMagicBubble(World world, double x, double y, double z){
super(world, x, y, z); super(world, x, y, z);
this.particleRed = 1.0F; this.setRBGColorF(1, 1, 1);
this.particleGreen = 1.0F;
this.particleBlue = 1.0F;
this.setParticleTextureIndex(32); this.setParticleTextureIndex(32);
this.setSize(0.02F, 0.02F); this.setSize(0.02F, 0.02F);
this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F; this.particleScale *= this.rand.nextFloat() * 0.6F + 0.2F;
@@ -15,14 +15,11 @@ public class ParticleMagicFlame extends ParticleWizardry {
public ParticleMagicFlame(World world, double x, double y, double z){ public ParticleMagicFlame(World world, double x, double y, double z){
super(world, x, y, z); super(world, x, y, z);
// Not sure what these did but they sure as heck won't do anything now...
// TESTME: If it looks the same as before, delete these.
// this.motionX = this.motionX * 0.009999999776482582D + par8;
// this.motionY = this.motionY * 0.009999999776482582D + par10;
// this.motionZ = this.motionZ * 0.009999999776482582D + par12;
this.flameScale = 1 + world.rand.nextFloat(); this.flameScale = 1 + world.rand.nextFloat();
this.setRBGColorF(1, 1, 1); this.setRBGColorF(1, 1, 1);
this.particleAlpha = 1;
this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D)); this.particleMaxAge = (int)(2.0D / (Math.random() * 0.8D + 0.2D));
this.shaded = false;
// IDEA: Make the particles for ray spells collide properly and not spawn on the other side of stuff. // IDEA: Make the particles for ray spells collide properly and not spawn on the other side of stuff.
this.canCollide = false; this.canCollide = false;
this.setParticleTextureIndex(48); this.setParticleTextureIndex(48);
@@ -1,32 +1,31 @@
package electroblob.wizardry.client.particle; package electroblob.wizardry.client.particle;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.spell.Clairvoyance; import electroblob.wizardry.spell.Clairvoyance;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; 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.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
public class ParticlePath extends ParticleCustomTexture { @Mod.EventBusSubscriber(Side.CLIENT)
public class ParticlePath extends ParticleWizardry {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "particle/path");
"textures/particle/path_particles.png");
private final double originX, originY, originZ; private final double originX, originY, originZ;
public ParticlePath(World world, double x, double y, double z){ public ParticlePath(World world, double x, double y, double z){
super(world, x, y, z);
super(world, x, y, z, TEXTURE); // This particle only has 1 texture
this.originX = x; this.originX = x;
this.originY = y; this.originY = y;
this.originZ = z; this.originZ = z;
this.setParticleTextureIndex(0);
// Set to a constant to remove the randomness from Particle. // Set to a constant to remove the randomness from Particle.
this.particleScale = 1.25f; this.particleScale = 1.25f;
this.particleGravity = 0; this.particleGravity = 0;
@@ -35,23 +34,10 @@ public class ParticlePath extends ParticleCustomTexture {
this.setRBGColorF(1, 1, 1); this.setRBGColorF(1, 1, 1);
} }
@Override
public ResourceLocation getTexture(){
return TEXTURE;
}
@Override
protected int getXFrames(){
return 1;
}
@Override
protected int getYFrames(){
return 1;
}
@Override @Override
public void onUpdate(){ public void onUpdate(){
super.onUpdate();
this.prevPosX = this.posX; this.prevPosX = this.posX;
this.prevPosY = this.posY; this.prevPosY = this.posY;
@@ -77,19 +63,10 @@ public class ParticlePath extends ParticleCustomTexture {
} }
} }
@Override @SubscribeEvent
public void applyGLStateChanges(){ public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
GlStateManager.enableBlend(); event.getMap().registerSprite(TEXTURE);
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();
} }
} }
@@ -1,60 +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 ParticleRotatingSparkle extends ParticleSparkle {
private double angle;
private double radius;
private double speed;
public ParticleRotatingSparkle(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.radius = 1; // TODO: Find a suitable default value
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 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);
}
}
}
@@ -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);
}
}
}
@@ -1,39 +1,36 @@
package electroblob.wizardry.client.particle; package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; 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.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT) @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, private static final ResourceLocation[] TEXTURES = generateTextures("snow", 4);
"textures/particle/snow_particles.png");
public ParticleSnow(World world, double x, double y, double z){ 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.setVelocity(0, -0.02, 0);
this.particleScale *= 0.6f; this.particleScale *= 0.6f;
this.particleGravity = 0; this.particleGravity = 0;
this.canCollide = true; 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 @SubscribeEvent
public ResourceLocation getTexture(){ public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
return TEXTURE; for(ResourceLocation texture : TEXTURES){
} event.getMap().registerSprite(texture);
}
@Override
protected int getXFrames(){
return 4;
}
@Override
protected int getYFrames(){
return 4;
} }
} }
@@ -1,66 +1,55 @@
package electroblob.wizardry.client.particle; 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.util.ResourceLocation;
import net.minecraft.world.World; 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.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT) @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, // 8 different animation strips, 4 in each strip
"textures/particle/lightning_particles.png"); private static final ResourceLocation[][] TEXTURES = generateTextures("lightning", 8, 4);
public ParticleSpark(World world, double x, double y, double z){ 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. super(world, x, y, z, TEXTURES[world.rand.nextInt(TEXTURES.length)]);
this.setParticleTextureIndex(rand.nextInt(8) * 4);
this.particleScale *= 1.4f; this.particleScale *= 1.4f;
this.setRBGColorF(1, 1, 1);
this.shaded = false; this.shaded = false;
this.canCollide = 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 // @Override
public void onUpdate(){ // public void applyGLStateChanges(){
super.onUpdate(); // GlStateManager.enableBlend();
// Well this is handy! Looks like vanilla uses the texture index like this too. // GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
this.nextTextureIndexX(); // // TESTME: Are these two actually necessary?
} // GlStateManager.disableLighting();
// OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
@Override // }
public ResourceLocation getTexture(){ //
return TEXTURE; // @Override
} // public void undoGLStateChanges(){
// GlStateManager.disableBlend();
@Override // GlStateManager.enableLighting();
protected int getXFrames(){ // }
return 4;
} @SubscribeEvent
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
@Override for(ResourceLocation[] array : TEXTURES){
protected int getYFrames(){ for(ResourceLocation texture : array){
return 8; event.getMap().registerSprite(texture);
} }
}
@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();
} }
} }
@@ -1,24 +1,23 @@
package electroblob.wizardry.client.particle; package electroblob.wizardry.client.particle;
import electroblob.wizardry.Wizardry;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; 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.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT) @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, private static final ResourceLocation[] TEXTURES = generateTextures("sparkle", 11);
"textures/particle/sparkle_particles.png");
// Implementation of colour fading (perhaps these belong in ParticleWizardry?)
private float initialRed;
private float initialGreen;
private float initialBlue;
public ParticleSparkle(World world, double x, double y, double z){ 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.setRBGColorF(1, 1, 1);
this.particleMaxAge = 48 + this.rand.nextInt(12); this.particleMaxAge = 48 + this.rand.nextInt(12);
this.particleScale *= 0.75f; this.particleScale *= 0.75f;
@@ -27,30 +26,6 @@ public class ParticleSparkle extends ParticleCustomTexture {
this.shaded = false; 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 @Override
public void onUpdate(){ public void onUpdate(){
@@ -58,24 +33,14 @@ public class ParticleSparkle extends ParticleCustomTexture {
// Fading // Fading
if(this.particleAge > this.particleMaxAge / 2){ if(this.particleAge > this.particleMaxAge / 2){
this.setAlphaF( this.setAlphaF(1 - ((float)this.particleAge - (float)(this.particleMaxAge / 2)) / (float)this.particleMaxAge);
1.0F - ((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. */
} }
@@ -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 <i>instead</i> of overriding {@code renderParticle} directly, and inside render the particle <b>along
* the z-axis, starting at (0, 0, 0)</b> - it will be translated and rotated automatically.
* <p>
* <i>N.B. Other than transformations, no GL state changes are applied; these should be done within this method.</i>
*
* @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);
}
@@ -1,7 +1,20 @@
package electroblob.wizardry.client.particle; 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.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.minecraft.world.World;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; 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 * 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 * 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 * {@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.
* <p> * <p>
* The new system is as follows: * The new system is as follows:
* <p> * <p>
@@ -17,28 +30,94 @@ import net.minecraftforge.fml.relauncher.SideOnly;
* - Each particle class defines any relevant default values in its constructor, including velocity.<br> * - Each particle class defines any relevant default values in its constructor, including velocity.<br>
* - The particle builder then overwrites any other values that were set during building. * - The particle builder then overwrites any other values that were set during building.
* <p> * <p>
* 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 * 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. * needs to be defined when spawning the particle - but importantly, it can still be overridden if desired.
* *
* @author Electroblob * @author Electroblob
* @since Wizardry 4.2.0 * @since Wizardry 4.2.0
* @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder * @see electroblob.wizardry.util.ParticleBuilder ParticleBuilder
*/ */
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
public abstract class ParticleWizardry extends Particle { 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. */ /** True if the particle is shaded, false if the particle always renders at full brightness. Defaults to false. */
protected boolean shaded = 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
* <b>must</b> 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); 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 /** 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.*/ * the particle always renders at full brightness. Defaults to false.*/
public void setShaded(boolean shaded){ public void setShaded(boolean shaded){
@@ -50,9 +129,9 @@ public abstract class ParticleWizardry extends Particle {
this.particleGravity = gravity ? 1 : 0; this.particleGravity = gravity ? 1 : 0;
} }
/** Sets this particle's lifetime in ticks.*/ /** Sets this particle's collisions. True to enable block collisions, false to disable. Defaults to false.*/
public void setLifetime(int lifetime){ public void setCollisions(boolean canCollide){
this.particleMaxAge = lifetime; this.canCollide = canCollide;
} }
/** /**
@@ -67,25 +146,252 @@ public abstract class ParticleWizardry extends Particle {
this.motionZ = vz; 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. <i>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 <b>after</b> calling this method.</i>
* @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. * Sets the fade colour of the particle.
* @param r The red colour component * @param r The red colour component
* @param g The green 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){ public void setFadeColour(float r, float g, float b){
this.fadeRed = r; this.fadeRed = r;
this.fadeGreen = g; this.fadeGreen = g;
this.fadeBlue = b; 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 @Override
public int getBrightnessForRender(float partialTick){ public int getBrightnessForRender(float partialTick){
return shaded ? super.getBrightnessForRender(partialTick) : 15728880; 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 super.onUpdate();
* expressions) in the client proxy to link particle enum types to actual particle classes. */
// 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<n; i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i);
}
return textures;
}
/** Static helper method that generates a 2D m x n array of ResourceLocations using the particle file naming
* convention, which is the given stem plus an underscore plus the first index, plus an underscore plus the second
* index. Useful for animated particles that also pick a random animation strip. */
public static ResourceLocation[][] generateTextures(String stem, int m, int n){
ResourceLocation[][] textures = new ResourceLocation[m][n];
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
textures[i][j] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i + "_" + j);
}
}
return textures;
}
/** Simple particle factory interface which takes a world and a position and returns a particle. Used (via method
* references) in the client proxy to link particle enum types to actual particle classes. */
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
@FunctionalInterface @FunctionalInterface
public interface IWizardryParticleFactory { public interface IWizardryParticleFactory {
@@ -1,187 +0,0 @@
package electroblob.wizardry.client.renderer;
import java.util.Random;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.entity.EntityArc;
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.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderArc extends Render<EntityArc> {
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<numberOfSegments-1; i++){
double px2 = (random.nextDouble()*2-1)*vertexDither; // Maybe use Gaussians?
double py2 = (random.nextDouble()*2-1)*vertexDither;
double pz2 = pz + arcLength/(double)numberOfSegments; // For now they are all the same length
drawSegment(tessellator, layer, px, py, pz, px2, py2, pz2, thickness);
// Forks
if(random.nextFloat() < forkChance){
double px3=px, py3=py, pz3=pz;
for(int j=0; j<random.nextInt(maxForkSegments-1)+1; j++){
// Forks set their centreline to the x/y coordinates of the vertex they originate from
double px4 = px3 + (random.nextDouble()*2-1)*vertexDither;
double py4 = py3 + (random.nextDouble()*2-1)*vertexDither;
double pz4 = pz3 + minSegmentLength + random.nextDouble()*(maxSegmentLength - minSegmentLength);
drawSegment(tessellator, layer, px3, py3, pz3, px4, py4, pz4, thickness*0.8f);
// Forks of forks
if(random.nextFloat() < forkChance){
double px5 = px3 + (random.nextDouble()*2-1)*vertexDither;
double py5 = py3 + (random.nextDouble()*2-1)*vertexDither;
double pz5 = pz3 + minSegmentLength + random.nextDouble()*(maxSegmentLength - minSegmentLength);
drawSegment(tessellator, layer, px3, py3, pz3, px5, py5, pz5, thickness*0.6f);
}
px3 = px4;
py3 = py4;
pz3 = pz4;
}
}
px = px2;
py = py2;
pz = pz2;
}
// Last segment has a specific end position and cannot fork.
double px2 = freeEnd ? (random.nextDouble()*2-1)*vertexDither : 0;
double py2 = freeEnd ? (random.nextDouble()*2-1)*vertexDither : 0;
drawSegment(tessellator, layer, px, py, pz, px2, py2, arcLength, thickness);
}
}
GlStateManager.enableTexture2D();
GlStateManager.enableLighting();
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
/** 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:
// TODO: Extract these colours as constants
drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.25f*thickness, 255, 255, 255, 255);
break;
case 1:
drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, 0.6f*thickness, 200, 255, 255, 165);
break;
case 2:
drawShearedBox(buffer, x1, y1, z1, x2, y2, z2, thickness, 50, 150, 255, 75);
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, int r, int g, int b, int 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();
}
@Override
protected ResourceLocation getEntityTexture(EntityArc entity){
return null;
}
}
@@ -1,72 +0,0 @@
package electroblob.wizardry.client.renderer;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
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.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.ResourceLocation;
public class RenderLightningPulse extends Render<EntityLightningPulse> {
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;
}
}
@@ -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();
}
}
@@ -53,24 +53,13 @@ public class EntityBlizzard extends EntityMagicConstruct {
if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) if(!MagicDamage.isEntityImmune(DamageType.FROST, target))
target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 20, 0)); target.addPotionEffect(new PotionEffect(WizardryPotions.frost, 20, 0));
} }
}else{ }else{
for(int i=1; i<6; i++){
for(int i=1; i<12; i++){
float brightness = 0.5f + (rand.nextFloat() / 2); 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)
ParticleBuilder.create(Type.BLIZZARD) .time(100).scale(2).spin(rand.nextDouble() * 2.5 + 0.5, speed).spawn(world);
.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);
} }
} }
} }
@@ -53,7 +53,7 @@ public class EntityDecay extends EntityMagicConstruct {
ParticleBuilder.create(Type.DARK_MAGIC) ParticleBuilder.create(Type.DARK_MAGIC)
.pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) .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); .spawn(world);
} }
} }
@@ -66,8 +66,8 @@ public class EntityForcefield extends EntityMagicConstruct {
ParticleBuilder.create(Type.DUST) ParticleBuilder.create(Type.DUST)
.pos(this.posX + radius * Math.cos(yaw) * Math.cos(pitch), this.posY + 3 + radius * Math.sin(pitch), .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)) this.posZ + radius * Math.sin(yaw) * Math.cos(pitch))
.lifetime(48 + this.rand.nextInt(12)) .time(48 + this.rand.nextInt(12))
.colour(brightness, brightness, 1.0f).spawn(world); .clr(brightness, brightness, 1.0f).spawn(world);
} }
} }
} }
@@ -3,7 +3,6 @@ package electroblob.wizardry.entity.construct;
import java.util.List; import java.util.List;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.MagicDamage.DamageType;
@@ -98,24 +97,12 @@ public class EntityHammer extends EntityMagicConstruct {
if(this.isValidTarget(target)){ if(this.isValidTarget(target)){
if(!world.isRemote){ if(world.isRemote){
EntityArc arc = new EntityArc(world);
arc.setEndpointCoords(this.posX, this.posY + this.height - 0.1, this.posZ, target.posX, ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world);
target.posY + target.height / 2, target.posZ);
world.spawnEntity(arc); ParticleBuilder.spawnShockParticles(world, target.posX,
}else{ target.getEntityBoundingBox().minY + target.height, target.posZ);
// 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);
}
} }
target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, rand.nextFloat() * 0.4F + 1.5F); target.playSound(WizardrySounds.SPELL_SPARK, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
@@ -69,8 +69,8 @@ public class EntityHealAura extends EntityMagicConstruct {
ParticleBuilder.create(Type.SPARKLE) ParticleBuilder.create(Type.SPARKLE)
.pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle)) .pos(this.posX + radius * Math.cos(angle), this.posY, this.posZ + radius * Math.sin(angle))
.vel(0, 0.05, 0) .vel(0, 0.05, 0)
.lifetime(48 + this.rand.nextInt(12)) .time(48 + this.rand.nextInt(12))
.colour(1.0f, 1.0f, brightness) .clr(1.0f, 1.0f, brightness)
.spawn(world); .spawn(world);
} }
} }
@@ -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;
}
}
@@ -2,7 +2,6 @@ package electroblob.wizardry.entity.construct;
import java.util.List; import java.util.List;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.MagicDamage.DamageType;
@@ -11,7 +10,6 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.DamageSource; import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.world.World; import net.minecraft.world.World;
public class EntityLightningSigil extends EntityMagicConstruct { public class EntityLightningSigil extends EntityMagicConstruct {
@@ -65,25 +63,14 @@ public class EntityLightningSigil extends EntityMagicConstruct {
if(secondaryTarget != target && this.isValidTarget(secondaryTarget)){ if(secondaryTarget != target && this.isValidTarget(secondaryTarget)){
if(!world.isRemote){ if(world.isRemote){
EntityArc arc = new EntityArc(world);
arc.setEndpointCoords(target.posX, target.posY + target.height / 2, target.posZ, ParticleBuilder.create(Type.LIGHTNING).entity(target)
secondaryTarget.posX, secondaryTarget.posY + secondaryTarget.height / 2, .pos(0, target.height/2, 0).target(secondaryTarget).spawn(world);
ParticleBuilder.spawnShockParticles(world, secondaryTarget.posX,
secondaryTarget.getEntityBoundingBox().minY + secondaryTarget.height / 2,
secondaryTarget.posZ); 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, secondaryTarget.playSound(WizardrySounds.SPELL_SPARK, 1.0F,
@@ -140,12 +140,14 @@ public class EntityTornado extends EntityMagicConstruct {
if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW)
type = Type.SNOW; type = Type.SNOW;
double yPos1 = rand.nextDouble() * 8; if(type != null){
ParticleBuilder.create(type) double yPos1 = rand.nextDouble() * 8;
.pos(this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1, ParticleBuilder.create(type)
this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d)) .pos(this.posX + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d), this.posY + yPos1,
.lifetime(40 + rand.nextInt(10)) this.posZ + (rand.nextDouble() * 2 - 1) * (yPos1 / 3 + 0.5d))
.spawn(world); .time(40 + rand.nextInt(10))
.spawn(world);
}
} }
} }
} }
@@ -41,14 +41,17 @@ public class EntityDecoy extends EntitySummonedCreature {
@Override @Override
public void onDespawn(){ public void onDespawn(){
super.onDespawn(); super.onDespawn();
for(int i = 0; i < 20; i++){
ParticleBuilder.create(Type.DUST) if(world.isRemote){
.pos(this.posX + (this.rand.nextDouble() - 0.5) * this.width, this.getEntityBoundingBox().minY for(int i = 0; i < 20; i++){
+ this.rand.nextDouble() * this.height, this.posZ + (this.rand.nextDouble() - 0.5) * this.width) ParticleBuilder.create(Type.DUST)
.lifetime(40) .pos(this.posX + (this.rand.nextDouble() - 0.5) * this.width, this.getEntityBoundingBox().minY
.colour(0.2f, 1.0f, 0.8f) + this.rand.nextDouble() * this.height, this.posZ + (this.rand.nextDouble() - 0.5) * this.width)
.shaded(true) .time(40)
.spawn(world); .clr(0.2f, 1.0f, 0.8f)
.shaded(true)
.spawn(world);
}
} }
} }
@@ -221,7 +221,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
// 0.5F. // 0.5F.
double y = (double)((float)this.posY - 0.5F + rand.nextFloat()); double y = (double)((float)this.posY - 0.5F + rand.nextFloat());
double z = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); 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{ }else{
if(this.getHealth() < 10){ if(this.getHealth() < 10){
@@ -99,8 +99,8 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature
if(this.world.isRemote){ if(this.world.isRemote){
for(int i = 0; i < 30; i++){ for(int i = 0; i < 30; i++){
float brightness = 0.5f + (rand.nextFloat() / 2); float brightness = 0.5f + (rand.nextFloat() / 2);
ParticleBuilder.create(Type.SPARKLE, this).vel(0, -0.02, 0).lifetime(12 + rand.nextInt(8)) ParticleBuilder.create(Type.SPARKLE, this).vel(0, -0.02, 0).time(12 + rand.nextInt(8))
.colour(brightness, brightness + 0.1f, 1.0f).spawn(world); .clr(brightness, brightness + 0.1f, 1.0f).spawn(world);
} }
} }
} }
@@ -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(), .pos(this.posX - 0.5d + rand.nextDouble(), this.posY + this.height / 2 - 0.5d + rand.nextDouble(),
this.posZ - 0.5d + rand.nextDouble()) this.posZ - 0.5d + rand.nextDouble())
.vel(0, 0.05f, 0) .vel(0, 0.05f, 0)
.lifetime(20 + rand.nextInt(10)) .time(20 + rand.nextInt(10))
.colour(brightness, brightness + 0.1f, 1.0f) .clr(brightness, brightness + 0.1f, 1.0f)
.spawn(world); .spawn(world);
} }
} }
@@ -40,8 +40,8 @@ public class EntityLightningWraith extends EntityBlazeMinion {
if(this.world.isRemote){ if(this.world.isRemote){
for(int i = 0; i < 15; i++){ for(int i = 0; i < 15; i++){
float brightness = 0.3f + (rand.nextFloat() / 2); float brightness = 0.3f + (rand.nextFloat() / 2);
ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).time(20 + rand.nextInt(10))
.colour(brightness, brightness + 0.2f, 1.0f).spawn(world); .clr(brightness, brightness + 0.2f, 1.0f).spawn(world);
} }
} }
} }
@@ -125,8 +125,8 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
if(this.world.isRemote){ if(this.world.isRemote){
for(int i = 0; i < 15; i++){ for(int i = 0; i < 15; i++){
float brightness = rand.nextFloat() * 0.4f; float brightness = rand.nextFloat() * 0.4f;
ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).time(20 + rand.nextInt(10))
.colour(brightness, 0.0f, brightness).spawn(world); .clr(brightness, 0.0f, brightness).spawn(world);
} }
} }
} }
@@ -160,10 +160,10 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
float brightness = rand.nextFloat() * 0.2f; float brightness = rand.nextFloat() * 0.2f;
ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).lifetime(20 + rand.nextInt(10)) ParticleBuilder.create(Type.SPARKLE, this).vel(0, 0.05, 0).time(20 + rand.nextInt(10))
.colour(brightness, 0.0f, brightness).spawn(world); .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);
} }
} }
@@ -82,7 +82,7 @@ public class EntitySilverfishMinion extends EntitySilverfish implements ISummone
for(int i = 0; i < 15; i++){ for(int i = 0; i < 15; i++){
ParticleBuilder.create(Type.DARK_MAGIC) ParticleBuilder.create(Type.DARK_MAGIC)
.pos(this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat()) .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); .spawn(world);
} }
} }
@@ -110,7 +110,7 @@ public class EntitySpiderMinion extends EntityCaveSpider implements ISummonedCre
for(int i = 0; i < 15; i++){ for(int i = 0; i < 15; i++){
ParticleBuilder.create(Type.DARK_MAGIC) ParticleBuilder.create(Type.DARK_MAGIC)
.pos(this.posX + this.rand.nextFloat(), this.posY + this.rand.nextFloat(), this.posZ + this.rand.nextFloat()) .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); .spawn(world);
} }
} }
@@ -120,7 +120,7 @@ public class EntitySpiritHorse extends EntityHorse {
double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; double x = this.posX - this.width / 2 + this.rand.nextFloat() * width;
double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f;
double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; 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 x = this.posX - this.width / 2 + this.rand.nextFloat() * width;
double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f;
double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; 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. // Spirit horse disappears a short time after being dismounted.
@@ -89,7 +89,7 @@ public class EntitySpiritWolf extends EntityWolf {
double x = this.posX - this.width / 2 + this.rand.nextFloat() * width; double x = this.posX - this.width / 2 + this.rand.nextFloat() * width;
double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f;
double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; 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 x = this.posX - this.width / 2 + this.rand.nextFloat() * width;
double y = this.posY + this.height * this.rand.nextFloat() + 0.2f; double y = this.posY + this.height * this.rand.nextFloat() + 0.2f;
double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width; 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);
} }
} }
@@ -148,8 +148,9 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe
float brightness = rand.nextFloat() * 0.2f; float brightness = rand.nextFloat() * 0.2f;
double dy = this.rand.nextDouble() * (double)this.height; double dy = this.rand.nextDouble() * (double)this.height;
ParticleBuilder.create(Type.SPARKLE_ROTATING).pos(this.posX, this.posY + dy, this.posZ) ParticleBuilder.create(Type.SPARKLE).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); .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);
} }
} }
@@ -310,7 +310,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
// 0.5F. // 0.5F.
double y = (double)((float)this.posY - 0.5F + rand.nextFloat()); double y = (double)((float)this.posY - 0.5F + rand.nextFloat());
double z = (double)((float)this.posZ + rand.nextFloat() * 2 - 1.0F); 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{ }else{
if(this.getHealth() < 10){ if(this.getHealth() < 10){
@@ -308,7 +308,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData {
if(this.hasParticleEffect() && thisEntity.world.isRemote && thisEntity.world.rand.nextInt(8) == 0) if(this.hasParticleEffect() && thisEntity.world.isRemote && thisEntity.world.rand.nextInt(8) == 0)
ParticleBuilder.create(Type.DARK_MAGIC) ParticleBuilder.create(Type.DARK_MAGIC)
.pos(thisEntity.posX, thisEntity.posY + thisEntity.world.rand.nextDouble() * 1.5, thisEntity.posZ) .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); .spawn(thisEntity.world);
} }
@@ -47,10 +47,10 @@ public class EntityDarknessOrb extends EntityMagicProjectile {
float brightness = rand.nextFloat() * 0.2f; float brightness = rand.nextFloat() * 0.2f;
ParticleBuilder.create(Type.SPARKLE, this).lifetime(20 + rand.nextInt(10)) ParticleBuilder.create(Type.SPARKLE, this).time(20 + rand.nextInt(10))
.colour(brightness, 0.0f, brightness).spawn(world); .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){ if(this.ticksExisted > 150){
@@ -36,7 +36,7 @@ public class EntityDart extends EntityMagicArrow {
@Override @Override
public void tickInAir(){ public void tickInAir(){
if(this.world.isRemote){ 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);
} }
} }
@@ -39,16 +39,19 @@ public class EntityFirebomb extends EntityBomb {
// Particle effect // Particle effect
if(world.isRemote){ 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++){ for(int i = 0; i < 60 * blastMultiplier; i++){
ParticleBuilder.create(Type.MAGIC_FIRE, rand, posX, posY, posZ, 2*blastMultiplier, false) 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) 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){ if(!this.world.isRemote){
@@ -1,6 +1,8 @@
package electroblob.wizardry.entity.projectile; package electroblob.wizardry.entity.projectile;
import electroblob.wizardry.util.MagicDamage.DamageType; 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.entity.EntityLivingBase;
import net.minecraft.init.SoundEvents; import net.minecraft.init.SoundEvents;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -15,6 +17,8 @@ public class EntityForceArrow extends EntityMagicArrow {
@Override @Override
public void onEntityHit(EntityLivingBase entityHit){ public void onEntityHit(EntityLivingBase entityHit){
this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); 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 @Override
@@ -25,6 +29,13 @@ public class EntityForceArrow extends EntityMagicArrow {
@Override @Override
public void onBlockHit(){ public void onBlockHit(){
this.playSound(SoundEvents.ENTITY_FIREWORK_BLAST, 1.0F, 1.0F); 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 @Override
@@ -31,8 +31,8 @@ public class EntityForceOrb extends EntityBomb {
if(this.world.isRemote){ if(this.world.isRemote){
for(int j = 0; j < 20; j++){ for(int j = 0; j < 20; j++){
float brightness = 0.5f + (rand.nextFloat() / 2); float brightness = 0.5f + (rand.nextFloat() / 2);
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.25, true).lifetime(6) ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.25, true).time(6)
.colour(brightness, 1.0f, brightness + 0.2f).spawn(world); .clr(brightness, 1.0f, brightness + 0.2f).spawn(world);
} }
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0); this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
} }
@@ -47,11 +47,11 @@ public class EntityIceCharge extends EntityBomb {
for(int i = 0; i < 30 * blastMultiplier; i++){ for(int i = 0; i < 30 * blastMultiplier; i++){
ParticleBuilder.create(Type.ICE, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) 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; float brightness = 0.4f + rand.nextFloat() * 0.5f;
ParticleBuilder.create(Type.DARK_MAGIC, rand, this.posX, this.posY, this.posZ, 2 * blastMultiplier, false) 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);
} }
} }
@@ -46,7 +46,7 @@ public class EntityIceLance extends EntityMagicArrow {
if(this.world.isRemote){ if(this.world.isRemote){
for(int j = 0; j < 10; j++){ for(int j = 0; j < 10; j++){
ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) 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. // Parameters for sound: sound event name, volume, pitch.
@@ -41,9 +41,13 @@ public class EntityIceShard extends EntityMagicArrow {
public void onBlockHit(){ public void onBlockHit(){
// Adds a particle effect when the ice shard hits a block. // Adds a particle effect when the ice shard hits a block.
if(this.world.isRemote){ 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++){ for(int j = 0; j < 10; j++){
ParticleBuilder.create(Type.ICE, this.rand, this.posX, this.posY, this.posZ, 0.5, true) 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. // Parameters for sound: sound event name, volume, pitch.
@@ -32,6 +32,12 @@ public class EntityLightningArrow extends EntityMagicArrow {
} }
this.playSound(WizardrySounds.SPELL_SPARK, 1.0F, 1.0F); 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 @Override
@@ -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. */ /** Called when the projectile hits an entity. Override to add potion effects and such like. */
protected void onEntityHit(EntityLivingBase entityHit){} protected void onEntityHit(EntityLivingBase entityHit){}
/** Called when the projectile hits a block. Override to add sound effects and such like. */ /** Called when the projectile hits a block. Override to add sound effects and such like.
protected void onBlockHit(){} * @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 @Override
public void onUpdate(){ public void onUpdate(){
@@ -390,7 +392,7 @@ public abstract class EntityMagicArrow extends Entity implements IProjectile, IE
this.inGround = true; this.inGround = true;
this.arrowShake = 7; this.arrowShake = 7;
this.onBlockHit(); this.onBlockHit(raytraceresult);
if(this.stuckInBlock.getMaterial() != Material.AIR){ if(this.stuckInBlock.getMaterial() != Material.AIR){
this.stuckInBlock.getBlock().onEntityCollidedWithBlock(this.world, raytraceresult.getBlockPos(), this.stuckInBlock.getBlock().onEntityCollidedWithBlock(this.world, raytraceresult.getBlockPos(),
@@ -4,9 +4,14 @@ import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.SoundEvents; import net.minecraft.init.SoundEvents;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public class EntityMagicMissile extends EntityMagicArrow { 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. */ /** Creates a new magic missile in the given world. */
public EntityMagicMissile(World world){ public EntityMagicMissile(World world){
@@ -26,25 +31,32 @@ public class EntityMagicMissile extends EntityMagicArrow {
} }
@Override @Override
public void onBlockHit(){ public void onBlockHit(RayTraceResult hit){
if(this.world.isRemote) spawnImpactParticles(); 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));
private void spawnImpactParticles(){ ParticleBuilder.create(Type.FLASH).pos(vec).clr(1, 1, 0.65f).fade(0.85f, 0.5f, 0.8f).spawn(world);
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);
} }
@Override @Override
public void tickInAir(){ public void tickInAir(){
if(this.ticksExisted > 20){ if(this.ticksExisted > LIFETIME){
this.setDead(); this.setDead();
} }
if(this.world.isRemote){ if(this.world.isRemote){
ParticleBuilder.create(Type.SPARKLE).pos(this.posX, this.posY, this.posZ).lifetime(20 + rand.nextInt(10)) ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
.colour(0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2), 0.5f + (rand.nextFloat() / 2)).spawn(world); .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);
}
} }
} }
@@ -41,13 +41,17 @@ public class EntityPoisonBomb extends EntityBomb {
// Particle effect // Particle effect
if(world.isRemote){ 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++){ for(int i = 0; i < 60 * blastMultiplier; i++){
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).lifetime(35) ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).time(35)
.colour(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world); .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) 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 // Spawning this after the other particles fixes the rendering colour bug. It's a bit of a cheat, but it
// works pretty well. // works pretty well.
@@ -27,7 +27,11 @@ public class EntitySmokeBomb extends EntityBomb {
// Particle effect // Particle effect
if(world.isRemote){ 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); this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
for(int i = 0; i < 60 * blastMultiplier; i++){ for(int i = 0; i < 60 * blastMultiplier; i++){
this.world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.world.spawnParticle(EnumParticleTypes.SMOKE_LARGE,
@@ -37,7 +41,7 @@ public class EntitySmokeBomb extends EntityBomb {
float brightness = rand.nextFloat() * 0.3f; float brightness = rand.nextFloat() * 0.3f;
ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false) ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false)
.colour(brightness, brightness, brightness).spawn(world); .clr(brightness, brightness, brightness).spawn(world);
} }
} }
@@ -2,11 +2,11 @@ package electroblob.wizardry.entity.projectile;
import java.util.List; import java.util.List;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
@@ -65,19 +65,14 @@ public class EntitySparkBomb extends EntityBomb {
if(!this.world.isRemote){ if(!this.world.isRemote){
EntityArc arc = new EntityArc(this.world); target.playSound(WizardrySounds.ENTITY_SPARK_BOMB_CHAIN, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
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.attackEntityFrom( target.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK), MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK),
5.0f * damageMultiplier); 5.0f * damageMultiplier);
}else{ }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); ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ);
} }
} }
@@ -40,7 +40,6 @@ public class PotionFrost extends Potion implements ICustomPotionParticles {
@Override @Override
public void spawnCustomParticle(World world, double x, double y, double z){ 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 @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){ public void renderHUDEffect(int x, int y, PotionEffect effect, net.minecraft.client.Minecraft mc, float alpha){
mc.renderEngine.bindTexture(ICON); mc.renderEngine.bindTexture(ICON);
WizardryUtilities.drawTexturedRect(x + 3, y + 3, 0, 0, 18, 18, 18, 18); 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 @SubscribeEvent
@@ -30,11 +30,10 @@ public class Arc extends SpellRay {
if(WizardryUtilities.isLiving(target)){ if(WizardryUtilities.isLiving(target)){
if(!world.isRemote){ if(world.isRemote){
EntityArc arc = new EntityArc(world); // Rather neatly, the entity can be set here and if it's null nothing will happen.
arc.setEndpointCoords(caster.posX, caster.posY + 1, caster.posZ, target.posX, target.posY + target.height / 2, target.posZ); ParticleBuilder.create(Type.LIGHTNING).entity(caster)
world.spawnEntity(arc); .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world);
}else{
ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ);
} }
@@ -60,7 +60,7 @@ public class ArcaneJammer extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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); .spawn(world);
} }
@@ -89,7 +89,7 @@ public class Banish extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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); 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);
} }
} }
@@ -102,12 +102,11 @@ public class ChainLightning extends SpellRay {
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage);
} }
if(!world.isRemote){ if(world.isRemote){
EntityArc arc = new EntityArc(world);
arc.setEndpointCoords(caster.posX, caster.getEntityBoundingBox().minY + caster.height / 2, caster.posZ, ParticleBuilder.create(Type.LIGHTNING).entity(caster)
target.posX, target.getEntityBoundingBox().minY + target.height / 2, target.posZ); .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(target).spawn(world);
world.spawnEntity(arc);
}else{
ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ); ParticleBuilder.spawnShockParticles(world, target.posX, target.getEntityBoundingBox().minY + target.height/2, target.posZ);
} }
@@ -127,7 +127,7 @@ public class Clairvoyance extends Spell {
(nextPoint.x - point.x) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.x - point.x) / (float)PARTICLE_MOVEMENT_INTERVAL,
(nextPoint.y - point.y) / (float)PARTICLE_MOVEMENT_INTERVAL, (nextPoint.y - point.y) / (float)PARTICLE_MOVEMENT_INTERVAL,
(nextPoint.z - point.z) / (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();
path.incrementPathIndex(); path.incrementPathIndex();
@@ -136,7 +136,7 @@ public class Clairvoyance extends Spell {
point = path.getFinalPathPoint(); point = path.getFinalPathPoint();
ParticleBuilder.create(Type.PATH).pos(point.x + 0.5, point.y + 0.5, point.z + 0.5) 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 @SubscribeEvent
@@ -54,9 +54,9 @@ public class CurseOfSoulbinding extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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).clr(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.DARK_MAGIC).pos(x, y, z).clr(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.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(1, 0.8f, 1).spawn(world);
} }
@SubscribeEvent @SubscribeEvent
@@ -63,7 +63,7 @@ public class Entrapment extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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); 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);
} }
} }
@@ -53,7 +53,7 @@ public class FlamingWeapon extends Spell {
double x = caster.posX + world.rand.nextDouble() * 2 - 1; double x = caster.posX + world.rand.nextDouble() * 2 - 1;
double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
double z = caster.posZ + world.rand.nextDouble() * 2 - 1; 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);
} }
} }
@@ -41,11 +41,11 @@ public class Flight extends Spell {
double x = caster.posX - 1 + world.rand.nextDouble() * 2; double x = caster.posX - 1 + world.rand.nextDouble() * 2;
double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
double z = caster.posZ - 1 + world.rand.nextDouble() * 2; 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; x = caster.posX - 1 + world.rand.nextDouble() * 2;
y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
z = caster.posZ - 1 + world.rand.nextDouble() * 2; 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){ if(ticksInUse % 24 == 0){
@@ -52,8 +52,8 @@ public class FontOfMana extends Spell {
double y = caster.getEntityBoundingBox().minY; double y = caster.getEntityBoundingBox().minY;
double z = caster.posZ + radius * Math.sin(angle); double z = caster.posZ + radius * Math.sin(angle);
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).lifetime(50) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, 0.03, 0).time(50)
.colour(1, 1 - hue, 0.6f + hue).spawn(world); .clr(1, 1 - hue, 0.6f + hue).spawn(world);
} }
} }
@@ -50,13 +50,13 @@ public class ForestsCurse extends SpellAreaEffect {
float brightness = world.rand.nextFloat() / 4; float brightness = world.rand.nextFloat() / 4;
ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).vel(0, -0.2, 0) 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; brightness = world.rand.nextFloat() / 4;
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.05, 0).lifetime(50) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(0, -0.05, 0).time(50)
.colour(0.1f + brightness, 0.2f + brightness, 0).spawn(world); .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);
} }
} }
@@ -87,8 +87,8 @@ public class Freeze extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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); float brightness = 0.5f + (world.rand.nextFloat() / 2);
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8))
.colour(brightness, brightness + 0.1f, 1).spawn(world); .clr(brightness, brightness + 0.1f, 1).spawn(world);
ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world); ParticleBuilder.create(Type.SNOW).pos(x, y, z).spawn(world);
} }
@@ -59,7 +59,7 @@ public class FreezingWeapon extends Spell {
double x = caster.posX + world.rand.nextDouble() * 2 - 1; double x = caster.posX + world.rand.nextDouble() * 2 - 1;
double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
double z = caster.posZ + world.rand.nextDouble() * 2 - 1; 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);
} }
} }
@@ -104,9 +104,9 @@ public class FrostRay extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){
float brightness = world.rand.nextFloat(); float brightness = world.rand.nextFloat();
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).lifetime(8 + world.rand.nextInt(12)) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12))
.colour(0.4f + 0.6f * brightness, 0.6f + 0.4f*brightness, 1).spawn(world); .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).lifetime(8 + world.rand.nextInt(12)).spawn(world); ParticleBuilder.create(Type.SNOW).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(12)).spawn(world);
} }
} }
@@ -35,11 +35,11 @@ public class Glide extends Spell {
double x = caster.posX - 0.25 + world.rand.nextDouble() / 2; double x = caster.posX - 0.25 + world.rand.nextDouble() / 2;
double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + world.rand.nextDouble();
double z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; 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; x = caster.posX - 0.25 + world.rand.nextDouble() / 2;
y = caster.getEntityBoundingBox().minY + world.rand.nextDouble(); y = caster.getEntityBoundingBox().minY + world.rand.nextDouble();
z = caster.posZ - 0.25 + world.rand.nextDouble() / 2; 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){ if(ticksInUse % 24 == 0){
@@ -9,8 +9,8 @@ import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
@@ -49,10 +49,10 @@ public class GroupHeal extends Spell {
double x = caster.posX + world.rand.nextDouble() * 2 - 1; double x = caster.posX + world.rand.nextDouble() * 2 - 1;
double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
double z = caster.posZ + world.rand.nextDouble() * 2 - 1; 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, 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 x = caster.posX + world.rand.nextDouble() * 2 - 1;
double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
double z = caster.posZ + world.rand.nextDouble() * 2 - 1; 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, WizardryUtilities.playSoundAtPlayer(caster, WizardrySounds.SPELL_HEAL, 0.7F,
@@ -41,10 +41,10 @@ public class HealAlly extends SpellRay {
double x1 = (double)((float)entity.posX + world.rand.nextFloat() * 2 - 1.0f); 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 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); 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);
} }
} }
@@ -55,9 +55,9 @@ public class IceStatue extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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; float brightness = 0.5f + world.rand.nextFloat() * 0.5f;
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(12 + world.rand.nextInt(8)) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8))
.colour(brightness, brightness + 0.1f, 1.0f).spawn(world); .clr(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.SNOW).pos(x, y, z).time(20 + world.rand.nextInt(10)).spawn(world);
} }
} }
@@ -68,7 +68,7 @@ public class ImbueWeapon extends Spell {
double x = caster.posX + world.rand.nextDouble() * 2 - 1; double x = caster.posX + world.rand.nextDouble() * 2 - 1;
double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
double z = caster.posZ + world.rand.nextDouble() * 2 - 1; 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);
} }
} }
@@ -68,7 +68,7 @@ public class Intimidate extends Spell {
double x = caster.posX - 1 + world.rand.nextDouble() * 2; double x = caster.posX - 1 + world.rand.nextDouble() * 2;
double y = caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble() * 0.5; double y = caster.getEntityBoundingBox().minY + 1.5 + world.rand.nextDouble() * 0.5;
double z = caster.posZ - 1 + world.rand.nextDouble() * 2; 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); WizardryUtilities.playSoundAtPlayer(caster, SoundEvents.ENTITY_ENDERDRAGON_GROWL, 1.0f, 1.0f);
@@ -53,7 +53,7 @@ public class InvigoratingPresence extends Spell {
double y = caster.getEntityBoundingBox().minY; double y = caster.getEntityBoundingBox().minY;
double z = caster.posZ + radius * Math.sin(angle); 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);
} }
} }
@@ -54,7 +54,7 @@ public class InvokeWeather extends Spell {
double x = caster.posX + world.rand.nextDouble() * 2 - 1; double x = caster.posX + world.rand.nextDouble() * 2 - 1;
double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble(); double y = caster.getEntityBoundingBox().minY + caster.getEyeHeight() - 0.5 + world.rand.nextDouble();
double z = caster.posZ + world.rand.nextDouble() * 2 - 1; 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);
} }
} }
@@ -30,7 +30,7 @@ public class Levitation extends Spell {
double x = caster.posX - 0.25 + world.rand.nextDouble() * 0.5; double x = caster.posX - 0.25 + world.rand.nextDouble() * 0.5;
double y = caster.getEntityBoundingBox().minY; double y = caster.getEntityBoundingBox().minY;
double z = caster.posZ - 0.25 + world.rand.nextDouble() * 0.5; 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){ if(ticksInUse % 24 == 0 && world.isRemote){
Wizardry.proxy.playMovingSound(caster, WizardrySounds.SPELL_LOOP_SPARKLE, 0.5f, 1, false); Wizardry.proxy.playMovingSound(caster, WizardrySounds.SPELL_LOOP_SPARKLE, 0.5f, 1, false);
@@ -89,10 +89,10 @@ public class LifeDrain extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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 // 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)) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).time(8 + world.rand.nextInt(6))
.colour(0.5f, 0, 0).spawn(world); .clr(0.5f, 0, 0).spawn(world);
} }
} }
@@ -5,11 +5,12 @@ import java.util.List;
import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.SpellType;
import electroblob.wizardry.constants.Tier; import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType; 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.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
@@ -72,14 +73,10 @@ public class LightningPulse extends Spell {
} }
} }
if(!world.isRemote){ if(world.isRemote){
// Surely neither of the commented lines would have done anything? ParticleBuilder.create(Type.LIGHTNING_PULSE).pos(caster.posX, caster.getEntityBoundingBox().minY
EntityLightningPulse lightningpulse = new EntityLightningPulse(world); + WizardryUtilities.ANTI_Z_FIGHTING_OFFSET, caster.posZ)
lightningpulse.setPosition(caster.posX, caster.getEntityBoundingBox().minY, caster.posZ); .scale(modifiers.get(WizardryItems.blast_upgrade)).spawn(world);
//lightningpulse.setCaster(caster);
lightningpulse.lifetime = 7;
//lightningpulse.damageMultiplier = modifiers.get(SpellModifiers.POTENCY);
world.spawnEntity(lightningpulse);
} }
caster.swingArm(hand); caster.swingArm(hand);
@@ -3,7 +3,6 @@ package electroblob.wizardry.spell;
import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.SpellType;
import electroblob.wizardry.constants.Tier; import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType; 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.EnumFacing;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -71,23 +71,18 @@ public class LightningRay extends SpellRay {
BASE_DAMAGE * modifiers.get(SpellModifiers.POTENCY)); 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 // Particle effect
for(int i=0; i<5; i++){ for(int i=0; i<5; i++){
ParticleBuilder.create(Type.SPARK, target).spawn(world); ParticleBuilder.create(Type.SPARK, target).spawn(world);
} }
} }
return true;
} }
return false; return false;
@@ -101,21 +96,15 @@ public class LightningRay extends SpellRay {
@Override @Override
protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ 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 // 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){ 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 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));
EntityArc arc = new EntityArc(world);
arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, ParticleBuilder.create(Type.LIGHTNING).entity(caster)
caster.posX + caster.getLookVec().x * freeRange, .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(endpoint).spawn(world);
caster.posY + caster.getEyeHeight() + caster.getLookVec().y * freeRange,
caster.posZ + caster.getLookVec().z * freeRange);
arc.lifetime = 1;
world.spawnEntity(arc);
}
} }
return true; return true;
@@ -5,7 +5,6 @@ import java.util.List;
import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.SpellType; import electroblob.wizardry.constants.SpellType;
import electroblob.wizardry.constants.Tier; import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType; 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.EnumFacing;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -119,19 +119,20 @@ public class LightningWeb extends SpellRay {
@Override @Override
protected boolean onMiss(World world, EntityLivingBase caster, int ticksInUse, SpellModifiers modifiers){ 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 // 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){ 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); ParticleBuilder.create(Type.LIGHTNING).entity(caster)
arc.setEndpointCoords(caster.posX, caster.posY + 1.2, caster.posZ, .pos(caster != null ? origin.subtract(caster.getPositionVector()) : origin).target(endpoint).spawn(world);
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);
} }
} }
@@ -150,17 +151,16 @@ public class LightningWeb extends SpellRay {
MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage); MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK), damage);
} }
if(!world.isRemote){ 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);
}
}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 // Particle effect
for(int i=0; i<5; i++){ for(int i=0; i<5; i++){
ParticleBuilder.create(Type.SPARK, target).spawn(world); ParticleBuilder.create(Type.SPARK, target).spawn(world);
@@ -34,6 +34,7 @@ import net.minecraft.entity.passive.EntityPig;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public class Metamorphosis extends SpellRay { public class Metamorphosis extends SpellRay {
@@ -111,7 +112,7 @@ public class Metamorphosis extends SpellRay {
}else{ }else{
for(int i=0; i<5; i++){ 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);
} }
} }
} }
@@ -76,10 +76,10 @@ public class MindControl extends SpellRay {
for(int i=0; i<10; i++){ for(int i=0; i<10; i++){
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX,
target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) 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, ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX,
target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) 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);
} }
} }
@@ -57,7 +57,7 @@ public class MindTrick extends SpellRay {
for(int i=0; i<10; i++){ for(int i=0; i<10; i++){
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX, ParticleBuilder.create(Type.DARK_MAGIC, world.rand, target.posX,
target.getEntityBoundingBox().minY + target.getEyeHeight(), target.posZ, 0.25, false) 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);
} }
} }
@@ -53,8 +53,8 @@ public class Petrify extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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.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).colour(0.1f, 0.1f, 0.1f).spawn(world); ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.1f, 0.1f, 0.1f).spawn(world);
} }
} }
@@ -58,12 +58,12 @@ public class PlagueOfDarkness extends Spell {
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
particleZ = caster.posZ - 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) 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(); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
particleZ = caster.posZ - 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) 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(); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
@@ -68,8 +68,8 @@ public class Poison extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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.DARK_MAGIC).pos(x, y, z).clr(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.SPARKLE).pos(x, y, z).time(12 + world.rand.nextInt(8)).clr(0.1f, 0.4f, 0).spawn(world);
} }
} }
@@ -78,12 +78,12 @@ public class Shockwave extends Spell {
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
particleZ = caster.posZ - 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) 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(); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
particleZ = caster.posZ - 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) 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(); particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble();
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble();
@@ -87,7 +87,7 @@ public class Slime extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ 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); 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);
} }
} }
@@ -54,9 +54,9 @@ public class Snare extends SpellRay {
@Override @Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){ protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){
float brightness = world.rand.nextFloat() * 0.25f; float brightness = world.rand.nextFloat() * 0.25f;
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).lifetime(20 + world.rand.nextInt(8)) ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).time(20 + world.rand.nextInt(8))
.colour(brightness, brightness + 0.1f, 0).spawn(world); .clr(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.LEAF).pos(x, y, z).vel(0, -0.01, 0).time(40 + world.rand.nextInt(10)).spawn(world);
} }
} }

Some files were not shown because too many files have changed in this diff Show More